当前位置:网站首页>Security思想项目总结
Security思想项目总结
2022-07-30 09:28:00 【Fairy要carry】
目录
UserDetailService实现类完成认证思路,返回UserDetails
流程:
首先1.登录login会走这个认证的filter中的attemptAuthentication()方法,目的是获取用户名密码,2.核心是利用authenticationMangaer接口的authenticate()方法(参数里面用UsernamepasswordAuthenticationToken封装用户名密码)——>3.真实是调用provideManager实现的authenticate()方法,也就是AuthenticationManager的实现类——>4.方法里面调用了UserDetailService接口中的loadUserByUserName()方法——>5.这里的UserDetailService我们一般会在业务中实现这个接口重写loadUserByUserName()这个方法,目的是从数据库中得到用户信息和权限然后给UserDetails封装权限和用户信息,然后返回我们UserDetails里——>6.验证成功得到Authentication——>7.认证成功进入successfulAuthentication()方法,根据UserDetails生成用户名进而利用JWT生成唯一token,然后我们将用户名,用户权限存入redis,并且把token进行返回——>8.然后进入权限过滤器,调用doFilterInternal()方法,里面调用了getAuthentication()方法,目的是判断用户是否有权限——>9.getAuthentication()方法,首先会得到请求头中的token,这里我们会利用前端拦截器将认证过滤器返回的token存入cookie然后放入header中,我们会通过token进行解析得到用户名username,然后从redis中取出对应username的权限,对权限遍历将其封装到SimpleGrantedAuthority()中,最后将权限用户名,token全部封装到UsernamePasswordAuthenticationToken中进行返回
认证过滤器
package com.atguigu.security.filter;
import com.atguigu.eduservice.R;
import com.atguigu.eduservice.ResponseUtil;
import com.atguigu.security.entity.SecurityUser;
import com.atguigu.security.entity.User;
import com.atguigu.security.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>
*
* @author qy
* @since 2019-11-08
*/
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"));
}
/**
* 获取用户名和密码
* @param req
* @param res
* @return
* @throws AuthenticationException
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
try {
User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
//authenticate认证用户
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();
//生成token字符串
String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
//把用户名和权限信息传入redis中
redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());
//返回token
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());
}
}
UserDetailService实现类完成认证思路,返回UserDetails
package com.atguigu.aclservice.service.impl;
import com.atguigu.aclservice.service.PermissionService;
import com.atguigu.aclservice.service.UserService;
import com.atguigu.eduservice.exceptionHandler.GuliException;
import com.atguigu.security.entity.SecurityUser;
import com.atguigu.security.entity.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 自定义userDetailsService - 认证用户详情
* UserDetailsService是 security中的接口
* </p>
*
* @author qy
* @since 2019-11-08
*/
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
/***
* 根据账号获取用户信息
* @param username:
* @return: org.springframework.security.core.userdetails.UserDetails
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 从数据库中取出用户信息
com.atguigu.aclservice.entity.User user = userService.selectByUsername(username);
// 判断用户是否存在
if (null == user){
throw new GuliException(20001,"用户名或密码错误");
//throw new UsernameNotFoundException("用户名不存在!");
}
// 返回UserDetails实现类
User curUser = new User();
BeanUtils.copyProperties(user,curUser);
//根据用户did得到用户权限
List<String> authorities = permissionService.selectPermissionValueByUserId(user.getId());
//将user封装到SecurityUser中(也就是UserDetails),并且封装用户权限
SecurityUser securityUser = new SecurityUser(curUser);
securityUser.setPermissionValueList(authorities);
return securityUser;
}
}
权限过滤器
package com.atguigu.security.filter;
//import com.atguigu.commonutils.R;
//import com.atguigu.commonutils.ResponseUtil;
//import com.atguigu.serurity.security.TokenManager;
import com.atguigu.eduservice.R;
import com.atguigu.eduservice.ResponseUtil;
import com.atguigu.security.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>
*
* @author qy
* @since 2019-11-08
*/
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());
}
//TODO:问题代码
chain.doFilter(req, res);
}
/**
* 判断用户是否有权限
* @param request
* @return
*/
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;
}
}
Security配置类
package com.atguigu.security.config;
import com.atguigu.security.filter.TokenAuthenticationFilter;
import com.atguigu.security.filter.TokenLoginFilter;
import com.atguigu.security.security.DefaultPasswordEncoder;
import com.atguigu.security.security.TokenLogoutHandler;
import com.atguigu.security.security.TokenManager;
import com.atguigu.security.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>
*
* @author qy
* @since 2019-11-18
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;//查询数据库
private TokenManager tokenManager;//token生成
private DefaultPasswordEncoder defaultPasswordEncoder;//密码处理
private RedisTemplate redisTemplate;//操作redis
@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 /admin/acl/index
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/**","**/api/**","admin/**","**/acl/**",
"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
);
}
}

边栏推荐
- 代码随想录笔记_哈希_202 快乐数
- Shell系统学习之数组
- Beijing suddenly announced big news in the Metaverse
- EViews 12.0 software installation package download and installation tutorial
- Soft test system architects introductory tutorial | system operation and software maintenance
- 连接mysql报错WARN: Establishing SSL connection without server‘s identity verification is not recommended
- 软考 系统架构设计师 简明教程 | 案例分析 | 需求分析
- 大根堆的创建(视频讲解)
- Study Notes 10--Main Methods of Local Trajectory Generation
- Determine whether a tree is a complete binary tree - video explanation!!!
猜你喜欢

Detailed explanation of JVM memory layout, class loading mechanism and garbage collection mechanism

Baidu promotion assistant encounters duplicate keywords, verification errors, how to delete redundant ones with one click

conda 导出/导出配置好的虚拟环境

A near-perfect Unity full-platform hot update solution

新一代开源免费的终端工具,太酷了

论文阅读:SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers

Unified exception handling causes ResponseBodyAdvice to fail

Jenkins 如何玩转接口自动化测试?

leetcode 剑指 Offer 22. 链表中倒数第k个节点

Redis Desktop Manager 2022.4.2 发布
随机推荐
JCL 学习
Flask之路由(app.route)详解
MySQL之COUNT性能到底如何?
大数据产品:标签体系0-1搭建实践
PyQt5快速开发与实战 7.4 事件处理机制入门 and 7.5 窗口数据传递
Shell系统学习之数组
功能测试、UI自动化测试(web自动化测试)、接口自动化测试
新一代开源免费的终端工具,太酷了
BERT pre-training model series summary
快解析结合友加畅捷通t1飞跃版
柱状图 直方图 条形图 的区别
【 HMS core 】 【 】 the FAQ HMS Toolkit collection of typical questions 1
HR团队如何提升效率?人力资源RPA给你答案
(C language) file operation
Two solutions for Excel xlsx file not supported
Re18: Read the paper GCI Everything Has a Cause: Leveraging Causal Inference in Legal Text Analysis
0729放假自习
一个近乎完美的 Unity 全平台热更方案
105. Construct binary tree from preorder and inorder traversal sequence (video explanation!!)
Re21:读论文 MSJudge Legal Judgment Prediction with Multi-Stage Case Representation Learning in the Real