Spring Security 理解小记
JWT 框架图如下, 来自博客https://blog.csdn.net/shehun1/article/details/45394405 个人觉得还不错..
在开发中Spring boot 启用
加载WebSecurityConfig
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {// 使用自定义身份验证组件auth.authenticationProvider(new JwtAuthenticationProvider(userDetailsService));}@Overrideprotected void configure(HttpSecurity http) throws Exception {// 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf http.cors().and().csrf().disable().authorizeRequests()// 跨域预检请求.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()// web jars.antMatchers("/webjars/**").permitAll()// 查看SQL监控(druid).antMatchers("/druid/**").permitAll()// 首页和登录页面.antMatchers("/").permitAll().antMatchers("/login").permitAll()// swagger.antMatchers("/swagger-ui.html").permitAll().antMatchers("/swagger-resources").permitAll().antMatchers("/v2/api-docs").permitAll().antMatchers("/webjars/springfox-swagger-ui/**").permitAll()// 验证码.antMatchers("/captcha.jpg**").permitAll()// 服务监控.antMatchers("/actuator/**").permitAll()// 其他所有请求需要身份认证 .anyRequest().authenticated();// 退出登录处理器http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());// token验证过滤器http.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);}@Bean@Overridepublic AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();}}
第二配置Security实现
1: 继承 DaoAuthenticationProvider 类
public class JwtAuthenticationProvider extends DaoAuthenticationProvider {public JwtAuthenticationProvider(UserDetailsService userDetailsService) {setUserDetailsService(userDetailsService);}@Overrideprotected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {if (authentication.getCredentials() == null) {logger.debug("Authentication failed: no credentials provided");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));}String presentedPassword = authentication.getCredentials().toString();String salt = ((JwtUserDetails) userDetails).getSalt();// 覆写密码验证逻辑if (!new PasswordEncoder(salt).matches(userDetails.getPassword(), presentedPassword)) {logger.debug("Authentication failed: password does not match stored value");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));}}}
2:实现 UserDetails 接口
public class JwtUserDetails implements UserDetails {private static final long serialVersionUID = 1L;private String username;private String password;private String salt;private Collection<? extends GrantedAuthority> authorities;JwtUserDetails(String username, String password, String salt, Collection<? extends GrantedAuthority> authorities) {this.username = username;this.password = password;this.salt = salt;this.authorities = authorities;}@Overridepublic String getUsername() {return username;}@JsonIgnore@Overridepublic String getPassword() {return password;}public String getSalt() {return salt;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}@JsonIgnore@Overridepublic boolean isAccountNonExpired() {return true;}@JsonIgnore@Overridepublic boolean isAccountNonLocked() {return true;}@JsonIgnore@Overridepublic boolean isCredentialsNonExpired() {return true;}@JsonIgnore@Overridepublic boolean isEnabled() {return true;}}
3: 实现 UserDetailsService 接口
@Service public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate SysUserService sysUserService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SysUser user = sysUserService.findByName(username);if (user == null) {throw new UsernameNotFoundException("该用户不存在");}// 用户权限列表,根据用户拥有的权限标识与如 @PreAuthorize("hasAuthority('sys:menu:view')") 标注的接口对比,决定是否可以调用接口Set<String> permissions = sysUserService.findPermissions(user.getName());List<GrantedAuthority> grantedAuthorities = permissions.stream().map(GrantedAuthorityImpl::new).collect(Collectors.toList());return new JwtUserDetails(user.getName(), user.getPassword(), user.getSalt(), grantedAuthorities);} }
4: 认证对象 继承 GrantedAuthority
public class GrantedAuthorityImpl implements GrantedAuthority {private static final long serialVersionUID = 1L;private String authority;public GrantedAuthorityImpl(String authority) {this.authority = authority;}public void setAuthority(String authority) {this.authority = authority;}@Overridepublic String getAuthority() {return this.authority;} }
5:JWT 的认证令牌对象 用于登录时创建一个
package com.louis.kitty.admin.security;import java.util.Collection;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority;/*** 自定义令牌对象* @author Louis* @date Nov 21, 2018*/ public class JwtAuthenticatioToken extends UsernamePasswordAuthenticationToken {private static final long serialVersionUID = 1L;private String token;public JwtAuthenticatioToken(Object principal, Object credentials){super(principal, credentials);}public JwtAuthenticatioToken(Object principal, Object credentials, String token){super(principal, credentials);this.token = token;}public JwtAuthenticatioToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities, String token) {super(principal, credentials, authorities);this.token = token;}public String getToken() {return token;}public void setToken(String token) {this.token = token;}public static long getSerialversionuid() {return serialVersionUID;}}
6:配置Security工具类
package com.louis.kitty.admin.util;import javax.servlet.http.HttpServletRequest;import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;import com.louis.kitty.admin.security.JwtAuthenticatioToken;/*** Security相关操作* @author Louis* @date Nov 20, 2018*/ public class SecurityUtils {/*** 系统登录认证* @param request* @param username* @param password* @param authenticationManager* @return*/public static JwtAuthenticatioToken login(HttpServletRequest request, String username, String password, AuthenticationManager authenticationManager) {JwtAuthenticatioToken token = new JwtAuthenticatioToken(username, password);token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));// 执行登录认证过程Authentication authentication = authenticationManager.authenticate(token);// 认证成功存储认证信息到上下文 SecurityContextHolder.getContext().setAuthentication(authentication);// 生成令牌并返回给客户端 token.setToken(JwtTokenUtils.generateToken(authentication));return token;}/*** 获取令牌进行认证* @param request*/public static void checkAuthentication(HttpServletRequest request) {// 获取令牌并根据令牌获取登录认证信息Authentication authentication = JwtTokenUtils.getAuthenticationeFromToken(request);// 设置登录认证信息到上下文 SecurityContextHolder.getContext().setAuthentication(authentication);}/*** 获取当前用户名* @return*/public static String getUsername() {String username = null;Authentication authentication = getAuthentication();if(authentication != null) {Object principal = authentication.getPrincipal();if(principal != null && principal instanceof UserDetails) {username = ((UserDetails) principal).getUsername();}}return username;}/*** 获取用户名* @return*/public static String getUsername(Authentication authentication) {String username = null;if(authentication != null) {Object principal = authentication.getPrincipal();if(principal != null && principal instanceof UserDetails) {username = ((UserDetails) principal).getUsername();}}return username;}/*** 获取当前登录信息* @return*/public static Authentication getAuthentication() {if(SecurityContextHolder.getContext() == null) {return null;}Authentication authentication = SecurityContextHolder.getContext().getAuthentication();return authentication;}}
7: 登录处理
@Autowiredprivate AuthenticationManager authenticationManager;
// 系统登录认证 JwtAuthenticatioToken token = SecurityUtils.login(request, username, password, authenticationManager);
8: 生成Token工具类
package com.louis.kitty.admin.util; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority;import com.louis.kitty.admin.security.GrantedAuthorityImpl; import com.louis.kitty.admin.security.JwtAuthenticatioToken;import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm;/*** JWT工具类* @author Louis* @date Nov 20, 2018*/ public class JwtTokenUtils implements Serializable {private static final long serialVersionUID = 1L;/*** 用户名称*/private static final String USERNAME = Claims.SUBJECT;/*** 创建时间*/private static final String CREATED = "created";/*** 权限列表*/private static final String AUTHORITIES = "authorities";/*** 密钥*/private static final String SECRET = "abcdefgh";/*** 有效期12小时*/private static final long EXPIRE_TIME = 12 * 60 * 60 * 1000;/*** 生成令牌** @param userDetails 用户* @return 令牌*/public static String generateToken(Authentication authentication) {Map<String, Object> claims = new HashMap<>(3);claims.put(USERNAME, SecurityUtils.getUsername(authentication));claims.put(CREATED, new Date());claims.put(AUTHORITIES, authentication.getAuthorities());return generateToken(claims);}/*** 从数据声明生成令牌** @param claims 数据声明* @return 令牌*/private static String generateToken(Map<String, Object> claims) {Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, SECRET).compact();}/*** 从令牌中获取用户名** @param token 令牌* @return 用户名*/public static String getUsernameFromToken(String token) {String username;try {Claims claims = getClaimsFromToken(token);username = claims.getSubject();} catch (Exception e) {username = null;}return username;}/*** 根据请求令牌获取登录认证信息* @param token 令牌* @return 用户名*/public static Authentication getAuthenticationeFromToken(HttpServletRequest request) {Authentication authentication = null;// 获取请求携带的令牌String token = JwtTokenUtils.getToken(request);if(token != null) {// 请求令牌不能为空if(SecurityUtils.getAuthentication() == null) {// 上下文中Authentication为空Claims claims = getClaimsFromToken(token);if(claims == null) {return null;}String username = claims.getSubject();if(username == null) {return null;}if(isTokenExpired(token)) {return null;}Object authors = claims.get(AUTHORITIES);List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();if (authors != null && authors instanceof List) {for (Object object : (List) authors) {authorities.add(new GrantedAuthorityImpl((String) ((Map) object).get("authority")));}}authentication = new JwtAuthenticatioToken(username, null, authorities, token);} else {if(validateToken(token, SecurityUtils.getUsername())) {// 如果上下文中Authentication非空,且请求令牌合法,直接返回当前登录认证信息authentication = SecurityUtils.getAuthentication();}}}return authentication;}/*** 从令牌中获取数据声明** @param token 令牌* @return 数据声明*/private static Claims getClaimsFromToken(String token) {Claims claims;try {claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();} catch (Exception e) {claims = null;}return claims;}/*** 验证令牌* @param token* @param username* @return*/public static Boolean validateToken(String token, String username) {String userName = getUsernameFromToken(token);return (userName.equals(username) && !isTokenExpired(token));}/*** 刷新令牌* @param token* @return*/public static String refreshToken(String token) {String refreshedToken;try {Claims claims = getClaimsFromToken(token);claims.put(CREATED, new Date());refreshedToken = generateToken(claims);} catch (Exception e) {refreshedToken = null;}return refreshedToken;}/*** 判断令牌是否过期** @param token 令牌* @return 是否过期*/public static Boolean isTokenExpired(String token) {try {Claims claims = getClaimsFromToken(token);Date expiration = claims.getExpiration();return expiration.before(new Date());} catch (Exception e) {return false;}}/*** 获取请求token* @param request* @return*/public static String getToken(HttpServletRequest request) {String token = request.getHeader("Authorization");String tokenHead = "Bearer ";if(token == null) {token = request.getHeader("token");} else if(token.contains(tokenHead)){token = token.substring(tokenHead.length());} if("".equals(token)) {token = null;}return token;}}
方法调用权限使用
转载于:https://www.cnblogs.com/eason-d/p/10722780.html
Spring Security 理解小记相关推荐
- Spring Security 实战干货: RBAC权限控制概念的理解
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 码农小胖哥 来源 | 公众号「码农小胖哥」 1 ...
- 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统
<深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...
- 【闲聊杂谈】深入理解Spring Security设计原理
1.什么是Spring Security 顾名思义,Security的意思是安全,本质上就是一个很纯粹的权限管理框架,提供认证和授权两大核心功能.在目前主流的Spring生态中的项目,说到安全框架,基 ...
- Spring Security并没有那么难嗷 简单理解OAuth2.0
文章目录 1. 基本概念 1.1 什么是认证 1.2 什么是会话 1.3 什么是授权 1.4 授权的数据模型 1.5 RBAC 1.5.1 基于角色的访问控制 1.5.2 基于资源的访问控制 2. 基 ...
- 理解Spring Security中permitAll()和anonymous()的区别
从 Spring文档: 采用"默认拒绝"通常被认为是良好的安全实践,您可以明确指定允许的内容并禁止其他所有内容.定义未经身份验证的用户可以访问的内容是类似的情况,尤其是对于 Web ...
- Spring Security简单理解
最近在学习Spring Security,于是就写了这篇Spring Security的博客来记录自己的学习中的一些总结,本文主要是一些简单的原理分析,没有涉及很深的源码分析. 1. Spring S ...
- spring security 简单理解
一.简介 Spring Security 是 Spring 家族中的一个安全管理框架. 一般来说,常见的安全管理技术栈的组合是这样的: SSM + Shiro Spring Boot/Spring C ...
- Spring Security 实战干货:自定义异常处理
Spring Security 实战干货:自定义异常处理 转自:https://www.cnblogs.com/felordcn/p/12142514.html 文章目录 1. 前言 2. Sprin ...
- Spring Security 中最流行的权限管理模型!
前面和大家说了 ACL,讲了理论,也给了一个完整的案例,相信小伙伴们对于 ACL 权限控制模型都已经比较了解了. 本文我要和大家聊一聊另外一个非常流行的权限管理模型,那就是 RBAC. 1.RBAC ...
最新文章
- 软件测试培训:高薪测试技术要掌握哪些
- 脑与神经类开放数据库汇总
- 【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )
- 七周三次课(1月24日) 10.11 Linux网络相关 10.12 firewalld和netfilter 10.13 netfilter5表5链介绍 10.14 iptables语法...
- 致所有.Net者和有梦想的朋友们 - 共勉
- YBTOJ:染颜色(KDtree)
- ejb的maven_针对新手的Java EE7和Maven项目-第3部分-定义ejb服务和jpa实体模块
- 游戏笔记本计算机购买,2021大学生买电脑,容易犯的七种错误!游戏本和轻薄本买哪个?...
- VMware NAT模式设置静态IP(可上网)
- 自学python-自学编程的6种方法,自学Python
- [Objective-C]用Block实现链式编程
- 开源有限元程序AsFem
- flask python 上传图片或头像
- 一位资深程序员大牛给予Java初学者的学习建议
- Filler Cell 与 Metal Fill差异
- 【泛微E-Mobile】管理员是否可以监控群聊
- idea如何连接达梦数据库
- TPshop项目-功能测试(2)
- Android8.0,允许安装未知来源
- 三分钟读懂:云计算与虚拟化的关系
热门文章
- 让apache支持mysql_Apache+PHP+Mysql环境搭建之三:配置Apache支持PHP
- android fragment 教程,Android app开发中的Fragment入门学习教程
- vos2009 校验版本超时_开源多云应用平台 Choerodon猪齿鱼发布0.14版本
- python远程linux服务器执行命令_基于使用paramiko执行远程linux主机命令(详解)
- pycharm去除波浪线的方法
- 计算尖峰电流的目的_干货 | 谈谈RCD的计算方法
- 安卓9.0官方系统升级包_想升级鸿蒙系统都来看看!华为新系统升级名单曝光:有你手机吗?...
- linux删除eth2设备_Linux卸载/删除多余网卡
- 目前人工智能技术趋势如何?
- mac下的git的安装与简单的配置