作者:王帅@CodeSheep

写在前面

关于 Spring Security

Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求。在Java EE领域,成熟的安全框架解决方案一般有 Apache Shiro、Spring Security等两种技术选型。Apache Shiro简单易用也算是一大优势,但其功能还是远不如 Spring Security强大。Spring Security可以为 Spring 应用提供声明式的安全访问控制,起通过提供一系列可以在 Spring应用上下文中可配置的Bean,并利用 Spring IoC和 AOP等功能特性来为应用系统提供声明式的安全访问控制功能,减少了诸多重复工作。

关于JWT

JSON Web Token (JWT),是在网络应用间传递信息的一种基于 JSON的开放标准((RFC 7519),用于作为JSON对象在不同系统之间进行安全地信息传输。主要使用场景一般是用来在 身份提供者和服务提供者间传递被认证的用户身份信息。关于JWT的科普,可以看看阮一峰老师的《JSON Web Token 入门教程》。

本文则结合 Spring Security和 JWT两大利器来打造一个简易的权限系统。

本文实验环境如下:

  • Spring Boot版本: 2.0.6.RELEASE

  • IDE: IntelliJIDEA2018.2.4

另外本文实验代码置于文尾,需要自取。


设计用户和角色

本文实验为了简化考虑,准备做如下设计:

  • 设计一个最简角色表 role,包括 角色ID和 角色名称

  • 设计一个最简用户表 user,包括 用户ID, 用户名, 密码

  • 再设计一个用户和角色一对多的关联表 user_roles 一个用户可以拥有多个角色


创建 Spring Security和 JWT加持的 Web工程

  • pom.xml 中引入 Spring Security和 JWT所必需的依赖

  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-security</artifactId>

  4. </dependency>

  5. <dependency>

  6. <groupId>io.jsonwebtoken</groupId>

  7. <artifactId>jjwt</artifactId>

  8. <version>0.9.0</version>

  9. </dependency>

  • 项目配置文件中加入数据库和 JPA等需要的配置

  1. server.port=9991

  2. spring.datasource.driver-class-name=com.mysql.jdbc.Driver

  3. spring.datasource.url=jdbc:mysql://121.196.XXX.XXX:3306/spring_security_jwt?useUnicode=true&characterEncoding=utf-8

  4. spring.datasource.username=root

  5. spring.datasource.password=XXXXXX

  6. logging.level.org.springframework.security=info

  7. spring.jpa.hibernate.ddl-auto=update

  8. spring.jpa.show-sql=true

  9. spring.jackson.serialization.indent_output=true

  • 创建用户、角色实体

用户实体 User

  1. /**

  2. * @ www.codesheep.cn

  3. * 20190312

  4. */

  5. @Entity

  6. public class User implements UserDetails {

  7. @Id

  8. @GeneratedValue

  9. private Long id;

  10. private String username;

  11. private String password;

  12. @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)

  13. private List<Role> roles;

  14. ...

  15. // 下面为实现UserDetails而需要的重写方法!

  16. @Override

  17. public Collection<? extends GrantedAuthority> getAuthorities() {

  18. List<GrantedAuthority> authorities = new ArrayList<>();

  19. for (Role role : roles) {

  20. authorities.add( new SimpleGrantedAuthority( role.getName() ) );

  21. }

  22. return authorities;

  23. }

  24. ...

  25. }

此处所创建的 User类继承了 Spring Security的 UserDetails接口,从而成为了一个符合 Security安全的用户,即通过继承 UserDetails,即可实现 Security中相关的安全功能。

角色实体 Role:

  1. /**

  2. * @ www.codesheep.cn

  3. * 20190312

  4. */

  5. @Entity

  6. public class Role {

  7. @Id

  8. @GeneratedValue

  9. private Long id;

  10. private String name;

  11. ... // 省略 getter和 setter

  12. }

  • 创建JWT工具类

主要用于对 JWT Token进行各项操作,比如生成Token、验证Token、刷新Token等

  1. /**

  2. * @ www.codesheep.cn

  3. * 20190312

  4. */

  5. @Component

  6. public class JwtTokenUtil implements Serializable {

  7. private static final long serialVersionUID = -5625635588908941275L;

  8. private static final String CLAIM_KEY_USERNAME = "sub";

  9. private static final String CLAIM_KEY_CREATED = "created";

  10. public String generateToken(UserDetails userDetails) {

  11. ...

  12. }

  13. String generateToken(Map<String, Object> claims) {

  14. ...

  15. }

  16. public String refreshToken(String token) {

  17. ...

  18. }

  19. public Boolean validateToken(String token, UserDetails userDetails) {

  20. ...

  21. }

  22. ... // 省略部分工具函数

  23. }

  • 创建Token过滤器,用于每次外部对接口请求时的Token处理

  1. /**

  2. * @ www.codesheep.cn

  3. * 20190312

  4. */

  5. @Component

  6. public class JwtTokenFilter extends OncePerRequestFilter {

  7. @Autowired

  8. private UserDetailsService userDetailsService;

  9. @Autowired

  10. private JwtTokenUtil jwtTokenUtil;

  11. @Override

  12. protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

  13. String authHeader = request.getHeader( Const.HEADER_STRING );

  14. if (authHeader != null && authHeader.startsWith( Const.TOKEN_PREFIX )) {

  15. final String authToken = authHeader.substring( Const.TOKEN_PREFIX.length() );

  16. String username = jwtTokenUtil.getUsernameFromToken(authToken);

  17. if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

  18. UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

  19. if (jwtTokenUtil.validateToken(authToken, userDetails)) {

  20. UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(

  21. userDetails, null, userDetails.getAuthorities());

  22. authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(

  23. request));

  24. SecurityContextHolder.getContext().setAuthentication(authentication);

  25. }

  26. }

  27. }

  28. chain.doFilter(request, response);

  29. }

  30. }

  • Service业务编写

主要包括用户登录和注册两个主要的业务

  1. public interface AuthService {

  2. User register( User userToAdd );

  3. String login( String username, String password );

  4. }

  1. /**

  2. * @ www.codesheep.cn

  3. * 20190312

  4. */

  5. @Service

  6. public class AuthServiceImpl implements AuthService {

  7. @Autowired

  8. private AuthenticationManager authenticationManager;

  9. @Autowired

  10. private UserDetailsService userDetailsService;

  11. @Autowired

  12. private JwtTokenUtil jwtTokenUtil;

  13. @Autowired

  14. private UserRepository userRepository;

  15. // 登录

  16. @Override

  17. public String login( String username, String password ) {

  18. UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken( username, password );

  19. final Authentication authentication = authenticationManager.authenticate(upToken);

  20. SecurityContextHolder.getContext().setAuthentication(authentication);

  21. final UserDetails userDetails = userDetailsService.loadUserByUsername( username );

  22. final String token = jwtTokenUtil.generateToken(userDetails);

  23. return token;

  24. }

  25. // 注册

  26. @Override

  27. public User register( User userToAdd ) {

  28. final String username = userToAdd.getUsername();

  29. if( userRepository.findByUsername(username)!=null ) {

  30. return null;

  31. }

  32. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

  33. final String rawPassword = userToAdd.getPassword();

  34. userToAdd.setPassword( encoder.encode(rawPassword) );

  35. return userRepository.save(userToAdd);

  36. }

  37. }

  • Spring Security配置类编写(非常重要)

这是一个高度综合的配置类,主要是通过重写 WebSecurityConfigurerAdapter 的部分 configure配置,来实现用户自定义的部分。

  1. /**

  2. * @ www.codesheep.cn

  3. * 20190312

  4. */

  5. @Configuration

  6. @EnableWebSecurity

  7. @EnableGlobalMethodSecurity(prePostEnabled=true)

  8. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  9. @Autowired

  10. private UserService userService;

  11. @Bean

  12. public JwtTokenFilter authenticationTokenFilterBean() throws Exception {

  13. return new JwtTokenFilter();

  14. }

  15. @Bean

  16. public AuthenticationManager authenticationManagerBean() throws Exception {

  17. return super.authenticationManagerBean();

  18. }

  19. @Override

  20. protected void configure( AuthenticationManagerBuilder auth ) throws Exception {

  21. auth.userDetailsService( userService ).passwordEncoder( new BCryptPasswordEncoder() );

  22. }

  23. @Override

  24. protected void configure( HttpSecurity httpSecurity ) throws Exception {

  25. httpSecurity.csrf().disable()

  26. .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

  27. .authorizeRequests()

  28. .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // OPTIONS请求全部放行

  29. .antMatchers(HttpMethod.POST, "/authentication/**").permitAll() //登录和注册的接口放行,其他接口全部接受验证

  30. .antMatchers(HttpMethod.POST).authenticated()

  31. .antMatchers(HttpMethod.PUT).authenticated()

  32. .antMatchers(HttpMethod.DELETE).authenticated()

  33. .antMatchers(HttpMethod.GET).authenticated();

  34. // 使用前文自定义的 Token过滤器

  35. httpSecurity

  36. .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter

转载于:https://www.cnblogs.com/bigben0123/p/10648689.html

Spring Boot 集成 Spring Security 实现权限认证模块相关推荐

  1. Spring Boot 集成spring security4

    项目GitHub地址 : https://github.com/FrameReserve/TrainingBoot Spring Boot (三)集成spring security,标记地址: htt ...

  2. Angular 6集成Spring Boot 2,Spring Security,JWT和CORS

    主要内容:Spring Boot 2的基础应用.CORS配置.Actuator监控:Spring Boot集成springfox-swagger,利用Swagger生成JSON API文档,利用Swa ...

  3. 认证与授权流程与spring boot整合 spring security(1)

    一   spring security 1.1 spring security的作用 Spring Security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截 ...

  4. 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序

    "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证. 开发人员 ...

  5. chrome charset使用_使用JWT保护你的Spring Boot应用 Spring Security实战

    关键词 Spring Boot.OAuth 2.0.JWT.Spring Security.SSO.UAA 写在前面 最近安静下来,重新学习一些东西,最近一年几乎没写过代码.整天疲于奔命的日子终于结束 ...

  6. 使用JWT保护你的Spring Boot应用 - Spring Security实战

    使用JWT保护你的Spring Boot应用 - Spring Security实战 作者 freewolf 原创文章转载请标明出处 关键词 Spring Boot.OAuth 2.0.JWT.Spr ...

  7. Spring Boot集成阿里云视频点播服务的过程记录

    阿里云视频点播 效果预览 视频点播 视频点播概述 功能 优势 流程 环境准备 开通视频点播 创建RAM用户并授权 上传SDK 上传流程 下载上传SDK 安装上传SDK 集成Java上传SDK 异常说明 ...

  8. 有手就行的 Spring Boot 集成 Shiro

    前言   Apache Shiro 是 Java 的一个安全框架.目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Se ...

  9. Spring Boot集成Jasypt安全框架

    Jasypt安全框架提供了Spring的集成,主要是实现 PlaceholderConfigurerSupport类或者其子类. 在Sring 3.1之后,则推荐使用PropertySourcesPl ...

  10. Spring Boot教程(十六):Spring Boot集成shiro

    Apache Shiro™是一个功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理.借助Shiro易于理解的API,您可以快速轻松地保护任何应用程序 - 从最小的移动应用程序到 ...

最新文章

  1. 我在兰亭这三年之自动化框架升级
  2. AWS副总裁Swami:现在是人工智能和机器学习的黄金时代
  3. “盗”亦有道,关于robots协议
  4. flume与Mosquitto的集成
  5. python 预编译加速_让Python代码运行更快的最佳方式
  6. stylus之内置方法(Built-in Functions)
  7. 运用Zabbix实现内网服务器状态及局域网状况监控(2) —— 环境配置
  8. 手机满足不了华为 华为拟在年底前发布带5G的8K电视!
  9. [bzoj1700]: [Usaco2007 Jan]Problem Solving 解题
  10. 花书+吴恩达深度学习(十二)卷积神经网络 CNN 之全连接层
  11. 手机触摸pass测试软件,PASS——功效分析和样本量计算软件
  12. 光谱共焦位移传感器原理
  13. VS2010 旗舰版和专业版 下载
  14. 油猴(Tampermonkey)使用教程
  15. DataCastle[猜你喜欢]赛事算法分享
  16. 设置gmail邮箱代收的方法
  17. 推荐大家一部好电影:当幸福来敲门
  18. “动力电池第三极“中创新航IPO,能否“复刻“宁德时代?
  19. 机器学习--西瓜书思维导图
  20. PCM设备的E1接头

热门文章

  1. dtoj#4258. 铃铛计数问题
  2. Sublime Text3的Package Control安装教程,及报错解决There Are No Packages Available For Installation...
  3. liunx查询进程下的线程
  4. Idea下的springboot mysql8.0等报错解决随笔
  5. webpack多环境(dev stg prd qa)打包问题
  6. Nginx域名重定向
  7. centos 5开机出现PCI错误:Not using MMCONFIG
  8. 在libvirt中使用SanLock
  9. 如何成为一名好的程序员的一些个人经验
  10. 码农们:你属于哪一种极品程序员?