当前位置:网站首页>Security Thought Project Summary
Security Thought Project Summary
2022-07-30 10:14:00 【Fairy wants to carry】
目录
UserDetailServiceThe realization class completes the authentication idea,返回UserDetails
流程:
首先1.登录loginWill take this certificationfilter中的attemptAuthentication()方法,The purpose is to get the username and password,2.核心是利用authenticationMangaer接口的authenticate()方法(used in parametersUsernamepasswordAuthenticationToken封装用户名密码)——>3.real is callingprovideManager实现的authenticate()方法,也就是AuthenticationManager的实现类——>4.方法里面调用了UserDetailService接口中的loadUserByUserName()方法——>5.这里的UserDetailServiceWe generally implement this interface rewrite in our businessloadUserByUserName()这个方法,The purpose is to get user information and permissions from the database and then give themUserDetailsEncapsulates permissions and user information,Then return to usUserDetails里——>6.Validation succeededAuthentication——>7.认证成功进入successfulAuthentication()方法,根据UserDetailsGenerate a username and use itJWT生成唯一token,Then we put the username,用户权限存入redis,并且把token进行返回——>8.Then go to the permission filter,调用doFilterInternal()方法,里面调用了getAuthentication()方法,The purpose is to determine whether the user has permission——>9.getAuthentication()方法,The first will get the request headertoken,Here we will use the front-end interceptor to return the authentication filtertoken存入cookie然后放入header中,我们会通过tokenParse to get the usernameusername,然后从redis中取出对应username的权限,Iterate over permissions封装到SimpleGrantedAuthority()中,最后Set the permission username,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());
//Pass in the username and permission informationredis中
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());
}
}
UserDetailServiceThe realization class completes the authentication idea,返回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),And encapsulate user permissions
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/**"
);
}
}

边栏推荐
- 容器技术 -- 简单了解 Kubernetes 的对象
- what is this method called
- debian10安装djando
- 初识Apifox——如何使用Apifox做一个简单的接口测试
- leetcode 剑指 Offer 58 - I. 翻转单词顺序
- Practical Walkthrough | Calculate Daily Average Date or Time Interval in MySQL
- 水电表预付费系统
- 线程池方式开启线程--submit()和execute()的区别
- Do you really understand the 5 basic data structures of Redis?
- The thread pool method opens the thread -- the difference between submit() and execute()
猜你喜欢
随机推荐
Re21:读论文 MSJudge Legal Judgment Prediction with Multi-Stage Case Representation Learning in the Real
论文阅读:SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers
Re19:读论文 Paragraph-level Rationale Extraction through Regularization: A case study on European Court
Basic operations of sequence table in C language
Paper reading: SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers
Domino Server SSL Certificate Installation Guide
快解析结合任我行crm
(Text) Frameless button settings
Determine whether a tree is a complete binary tree - video explanation!!!
在机器人行业的专业人士眼里,机器人行业目前的情况如何?
leetcode 剑指 Offer 47. 礼物的最大价值
快解析结合用友时空
Security思想项目总结
百度推广助手遇到重复关键字,验证错误,怎么一键删除多余的
功能测试、UI自动化测试(web自动化测试)、接口自动化测试
Detailed explanation of JVM memory layout, class loading mechanism and garbage collection mechanism
Re15:读论文 LEVEN: A Large-Scale Chinese Legal Event Detection Dataset
nacos实战项目中的配置
leetcode 剑指 Offer 57. 和为s的两个数字
Flask之路由(app.route)详解









