一、Spring Security介绍

1、框架介绍

Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的

安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。

  1. 用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。
  2. 用户授权指的是:验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

Spring Security其实就是用filter,多请求的路径进行过滤。

(1)如果是基于Session,那么Spring-security会对cookie里的sessionid进行解析,找到服务器存储的sesion信息,然后判断当前用户是否符合请求的要求。

(2)如果是基于token,则是解析出token,然后将当前请求加入到Spring-security管理的权限信息中去

2、认证与授权实现思路

如果系统的模块众多,每个模块都需要就行授权与认证,所以我们选择基于token的形式进行授权与认证,用户根据用户名密码认证成功,然后获取当前用户角色的一系列权限值,并以用户名为key,权限列表为value的形式存入redis缓存中,根据用户名相关信息生成token返回,浏览器将token记录到cookie中,每次调用api接口都默认将token携带到header请求头中,Spring-security解析header头获取token信息,解析token获取当前用户名,根据用户名就可以从redis中获取权限列表,这样Spring-security就能够判断当前请求是否有权限访问。



二、整合Spring Security

1、在common下创建spring_security模块

2、在spring_security引入相关依赖

<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> <!-- Spring Security依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> <dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>

3、在service_acl引入spring_security依赖

<dependency>
<groupId>com.atguigu</groupId>
<artifactId>spring_security</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

4、代码结构说明

5、创建spring security核心配置类

Spring Security的核心配置就是继承WebSecurityConfigurerAdapter并注解@EnableWebSecurity的配置。

这个配置指明了用户名密码的处理方式、请求路径的开合、登录登出控制等和安全相关的配置。

import com.atguigu.serurity.filter.TokenAuthenticationFilter;
import com.atguigu.serurity.filter.TokenLoginFilter;
import com.atguigu.serurity.security.DefaultPasswordEncoder;
import com.atguigu.serurity.security.TokenLogoutHandler;
import com.atguigu.serurity.security.TokenManager;
import com.atguigu.serurity.security.UnauthorizedEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService; /**
* <p>
* Security配置类
* </p>
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter { private UserDetailsService userDetailsService;
private TokenManager tokenManager;
private DefaultPasswordEncoder defaultPasswordEncoder;
private RedisTemplate redisTemplate; @Autowired
public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,
TokenManager tokenManager, RedisTemplate redisTemplate) {
this.userDetailsService = userDetailsService;
this.defaultPasswordEncoder = defaultPasswordEncoder;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
} /**
* 配置设置
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(new UnauthorizedEntryPoint())
.and().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().logout().logoutUrl("/admin/acl/index/logout")
.addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
.addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
.addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
} /**
* 密码处理
* @param auth
* @throws Exception
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
} /**
* 配置哪些请求不拦截
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/**",
"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
);
}
}

6、创建认证授权相关的工具类

6.1 DefaultPasswordEncoder:密码处理的方法

package com.atguigu.serurity.security;

import com.atguigu.commonutils.utils.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component; /**
* <p>
* 密码的处理方法类型
* </p>
*/
@Component
public class DefaultPasswordEncoder implements PasswordEncoder { public DefaultPasswordEncoder() {
this(-1);
} /**
* @param strength
* the log rounds to use, between 4 and 31
*/
public DefaultPasswordEncoder(int strength) { } public String encode(CharSequence rawPassword) {
return MD5.encrypt(rawPassword.toString());
} public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));
}
}

6.2 TokenManager:token操作的工具类

import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component; import java.util.Date; /**
* <p>
* token管理
* </p>
*/
@Component
public class TokenManager { private long tokenExpiration = 24*60*60*1000;
private String tokenSignKey = "123456"; public String createToken(String username) {
String token = Jwts.builder().setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
return token;
} public String getUserFromToken(String token) {
String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
return user;
} public void removeToken(String token) {
//jwttoken无需删除,客户端扔掉即可。
}
}

6.3 DefaultPasswordEncoder:密码处理的方法

import com.atguigu.commonutils.R;
import com.atguigu.commonutils.utils.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* <p>
* 登出业务逻辑类
* </p>
*/
public class TokenLogoutHandler implements LogoutHandler { private TokenManager tokenManager;
private RedisTemplate redisTemplate; public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
} @Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
String token = request.getHeader("token");
if (token != null) {
tokenManager.removeToken(token); //清空当前用户缓存中的权限数据
String userName = tokenManager.getUserFromToken(token);
redisTemplate.delete(userName);
}
ResponseUtil.out(response, R.ok());
}
}

6.4 UnauthorizedEntryPoint:未授权统一处理

import com.atguigu.commonutils.R;
import com.atguigu.commonutils.utils.ResponseUtil;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* <p>
* 未授权的统一处理方式
* </p>
*/
public class UnauthorizedEntryPoint implements AuthenticationEntryPoint { @Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException { ResponseUtil.out(response, R.error());
}
}

7、创建认证授权实体类

7.1 SecutityUser

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; /**
* <p>
* 安全认证用户详情信息
* </p>
*/
@Data
@Slf4j
public class SecurityUser implements UserDetails { //当前登录用户
private transient User currentUserInfo; //当前权限
private List<String> permissionValueList; public SecurityUser() {
} public SecurityUser(User user) {
if (user != null) {
this.currentUserInfo = user;
}
} @Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
for(String permissionValue : permissionValueList) {
if(StringUtils.isEmpty(permissionValue)) continue;
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
authorities.add(authority);
} return authorities;
} @Override
public String getPassword() {
return currentUserInfo.getPassword();
} @Override
public String getUsername() {
return currentUserInfo.getUsername();
} @Override
public boolean isAccountNonExpired() {
return true;
} @Override
public boolean isAccountNonLocked() {
return true;
} @Override
public boolean isCredentialsNonExpired() {
return true;
} @Override
public boolean isEnabled() {
return true;
}
}

7.2 User

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable; /**
* <p>
* 用户实体类
* </p>
*/
@Data
@ApiModel(description = "用户实体类")
public class User implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "微信openid")
private String username; @ApiModelProperty(value = "密码")
private String password; @ApiModelProperty(value = "昵称")
private String nickName; @ApiModelProperty(value = "用户头像")
private String salt; @ApiModelProperty(value = "用户签名")
private String token;
}

8、创建认证和授权的filter

8.1 TokenLoginFilter:认证的filter

import com.atguigu.commonutils.R;
import com.atguigu.commonutils.utils.ResponseUtil;
import com.atguigu.serurity.entity.SecurityUser;
import com.atguigu.serurity.entity.User;
import com.atguigu.serurity.security.TokenManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList; /**
* <p>
* 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验
* </p>
*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager;
private TokenManager tokenManager;
private RedisTemplate redisTemplate; public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
this.setPostOnly(false);
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST"));
} @Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
try {
User user = new ObjectMapper().readValue(req.getInputStream(), User.class); return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
} catch (IOException e) {
throw new RuntimeException(e);
} } /**
* 登录成功
* @param req
* @param res
* @param chain
* @param auth
* @throws IOException
* @throws ServletException
*/
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
SecurityUser user = (SecurityUser) auth.getPrincipal();
String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList()); ResponseUtil.out(res, R.ok().data("token", token));
} /**
* 登录失败
* @param request
* @param response
* @param e
* @throws IOException
* @throws ServletException
*/
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
ResponseUtil.out(response, R.error());
}
}

8.2 TokenAuthenticationFilter:授权filter

package com.atguigu.serurity.filter;

import com.atguigu.commonutils.R;
import com.atguigu.commonutils.utils.ResponseUtil;
import com.atguigu.serurity.security.TokenManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils; import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; /**
* <p>
* 访问过滤器
* </p>
*/
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate; public TokenAuthenticationFilter(AuthenticationManager authManager, TokenManager tokenManager,RedisTemplate redisTemplate) {
super(authManager);
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
} @Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
logger.info("================="+req.getRequestURI());
if(req.getRequestURI().indexOf("admin") == -1) {
chain.doFilter(req, res);
return;
} UsernamePasswordAuthenticationToken authentication = null;
try {
authentication = getAuthentication(req);
} catch (Exception e) {
ResponseUtil.out(res, R.error());
} if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
ResponseUtil.out(res, R.error());
}
chain.doFilter(req, res);
} private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
// token置于header里
String token = request.getHeader("token");
if (token != null && !"".equals(token.trim())) {
String userName = tokenManager.getUserFromToken(token); List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(userName);
Collection<GrantedAuthority> authorities = new ArrayList<>();
for(String permissionValue : permissionValueList) {
if(StringUtils.isEmpty(permissionValue)) continue;
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
authorities.add(authority);
} if (!StringUtils.isEmpty(userName)) {
return new UsernamePasswordAuthenticationToken(userName, token, authorities);
}
return null;
}
return null;
}
}

权限管理3-整合Spring Security的更多相关文章

  1. springBoot整合spring security实现权限管理(单体应用版)--筑基初期

    写在前面 在前面的学习当中,我们对spring security有了一个小小的认识,接下来我们整合目前的主流框架springBoot,实现权限的管理. 在这之前,假定你已经了解了基于资源的权限管理模型 ...

  2. springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期

    写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...

  3. SpringBoot整合Spring Security

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Securi ...

  4. Spring Boot整合Spring Security

    Spring Boot对于该家族的框架支持良好,但是当中本人作为小白配置还是有一点点的小问题,这里分享一下.这个项目是使用之前发布的Spring Boot会员管理系统重新改装,将之前filter登录验 ...

  5. Spring Boot整合Spring Security自定义登录实战

    本文主要介绍在Spring Boot中整合Spring Security,对于Spring Boot配置及使用不做过多介绍,还不了解的同学可以先学习下Spring Boot. 本demo所用Sprin ...

  6. SpringBoot安全篇Ⅵ --- 整合Spring Security

    知识储备: 关于SpringSecurity的详细学习可以查看SpringSecurity的官方文档. Spring Security概览 应用程序的两个主要区域是"认证"和&qu ...

  7. 【手摸手,带你搭建前后端分离商城系统】03 整合Spring Security token 实现方案,完成主业务登录

    [手摸手,带你搭建前后端分离商城系统]03 整合Spring Security token 实现方案,完成主业务登录 上节里面,我们已经将基本的前端 VUE + Element UI 整合到了一起.并 ...

  8. 【权限管理】springboot集成security

    摘自: https://www.cnblogs.com/hhhshct/p/9726378.html https://blog.csdn.net/weixin_42849689/article/det ...

  9. springboot+maven整合spring security

    springboot+maven整合spring security已经做了两次了,然而还是不太熟悉,这里针对后台简单记录一下需要做哪些事情,具体的步骤怎么操作网上都有,不再赘述.1.pom.xml中添 ...

随机推荐

  1. vue第十三单元(指令的作用,指令的钩子函数)

    第十三单元(指令的作用,指令的钩子函数) #课程目标 1.了解自定义指令的应用场景 2.掌握自定义全局和局部指令 3.掌握指令的钩子函数 #知识点 #一.认识自定义指令 除了核心功能默认内置的指令 ( ...

  2. C#数据结构-赫夫曼树

    什么是赫夫曼树? 赫夫曼树(Huffman Tree)是指给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小.哈夫曼树(也称为最优二叉树)是带权路径长度最短的树,权值较大的结点 ...

  3. Nebula Graph 在微众银行数据治理业务的实践

    本文为微众银行大数据平台:周可在 nMeetup 深圳场的演讲这里文字稿,演讲视频参见:B站 自我介绍下,我是微众银行大数据平台的工程师:周可,今天给大家分享一下 Nebula Graph 在微众银行 ...

  4. CentOS7服务器JDK8安装实战

    简介:演练JDK8环境的安装 下载jdk官网: https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133 ...

  5. [leetcode]75.Sort Color三指针

    import java.util.Arrays; /** * Given an array with n objects colored red,white or blue, * sort them ...

  6. JDK,JRE,JVM三者之间的关系和作用

    1,定义: JDK: Java Develpment Kit java 开发工具 bin:最主要的是编译器(javac.exe) include:java和JVM交互用的头文件 lib:类库 JRE: ...

  7. NIO非阻塞式编程

    /** * NIO非阻塞式编程<p> * 服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件. * 我们以服务端 ...

  8. java线程与内核线程的关系,及怎么定义ThreadPoolExecutor相关参数

    p.p1 { margin: 0; font: 12px Menlo } p.p1 { margin: 0; font: 12px Menlo } p.p2 { margin: 0; font: 12 ...

  9. 容器编排系统K8s之Dashboard部署

    前文我们了解了k8s的访问控制第三关准入控制相关插件的使用,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14220402.html:今天我们来了解下k8s的 ...

  10. [不止于代码]Unraid基本使用速记

    1.Unraid简介 Unraid是一个虚拟机系统,类似于VM.PVE,但又区别于前二者.通过Unraid的Dokcer可以快速构建类Nas及虚拟机环境,也可虚拟黑群晖使用,可以使用磁盘阵列,保护你的 ...