1.权限管理数据模型
添加角色
为角色分配菜单
添加用户
为用户分配角色
数据库建表
2.项目中用到的技术
maven(创建父工程:管理项目依赖版本,创建子模块:使用具体依赖)
springboot
mybatisPlus 操作数据库
springcloud (GateWay网关,注册中心nacos)
Redis
Jwt(生成token字符串)
Swagger
前端技术
3.搭建项目工程
整体流程
编写各种工具类
1.生成token
package com.atguigu.security;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class TokenManager {
//token有效时长
private long tokenEcpiration = 24*60*60*1000;
//编码秘钥
private String tokeSignKey = "123456";
//根据用户名生成token
public String createToken(String username){
String token = Jwts.builder().setSubject(username)
.setExpiration(new Date(System.currentTimeMillis()+tokenEcpiration))
.signWith(SignatureAlgorithm.ES512,tokeSignKey).compressWith(CompressionCodecs.GZIP).compact();
return token;
}
//根据token字符串得到用户信息
public String getUserInfoFromToken(String token){
String userInfo = Jwts.parser().setSigningKey(tokeSignKey).parseClaimsJws(token).getBody().getSubject();
return userInfo;
}
//删除token
public void removeToken(String token){
}
}
退出处理器
package com.atguigu.security;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
public class TokenLogoutHandler implements LogoutHandler {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenLogoutHandler(TokenManager tokenManager,RedisTemplate redisTemplate){
this.redisTemplate = redisTemplate;
this.tokenManager = tokenManager;
}
@Override
public void logout(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse res, Authentication authentication) {
//1.从header里获取token
//2.token不为空移除token,从Redis删除
String token = req.getHeader("token");
if(token!=null){
tokenManager.removeToken(token);
String username = tokenManager.getUserInfoFromToken(token);
redisTemplate.delete(username);
ResponseUtil.out(res,R.ok());
}
}
}
未授权同意处理类
package com.atguigu.security;
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;
public class UnauthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
ResponseUtil.out(response,R.error);
}
}
编写自定义认证过滤器
package com.atguigu.security.filter;
import com.atguigu.security.TokenManager;
import com.atguigu.security.entry.SecurityUser;
import com.atguigu.security.entry.User;
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.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.core.AuthenticationException;
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;
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
private AuthenticationManager authenticationManager;
public TokenLoginFilter(TokenManager tokenManager, RedisTemplate redisTemplate, AuthenticationManager authenticationManager) {
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
this.authenticationManager = authenticationManager;
this.setPostOnly(false);
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin.acl/login","POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//获取表单提交的工具
try {
User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword()
,new ArrayList<>()));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//认证成功后,先得到认证成功信息
SecurityUser user = (SecurityUser)authResult.getPrincipal();
//根据用户名生成token
String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
//把信息放入redis
redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(),user.getPermissionValueList());
//返回token
//ResponseUtil.out(reponse,R.ok().data("token",token));
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException failed) throws IOException, ServletException {
//ResponseUtil.out(reponse,R.error());
}
}
授权过滤器
package com.atguigu.security.filter;
import com.atguigu.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.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
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;
public class TokenAuthFilter extends BasicAuthenticationFilter {
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenAuthFilter(AuthenticationManager authenticationManager,TokenManager tokenManager,RedisTemplate redisTemplate) {
super(authenticationManager);
this.redisTemplate = redisTemplate;
this.tokenManager = tokenManager;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
//获取当前认证成功用户信息
UsernamePasswordAuthenticationToken authRequest = getAuthentication(request);
//判断如果有权限信息,放入权限上下文中
if(authRequest!=null){
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
chain.doFilter(request,response);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
//从Header 获取token
String token = request.getHeader("token");
if(token!=null){
//从token中获取用户名
String username = tokenManager.getUserInfoFromToken(token);
List<String> permissonValueList = (List<String>) redisTemplate.opsForValue().get(username);
Collection<GrantedAuthority> authorities = new ArrayList<>();
for (String p:permissonValueList) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(p);
authorities.add(authority);
}
return new UsernamePasswordAuthenticationToken(username,token,authorities);
}
return null;
}
}
编写userDetailsService查询数据库的数据