spring boot 整合Spring Security

爱被打了一巴掌 2022-04-05 12:47 390阅读 0赞

Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

实体类

  1. package com.springsecutity.secutity.entity;
  2. import javax.persistence.Entity;
  3. import javax.persistence.GeneratedValue;
  4. import javax.persistence.Id;
  5. @Entity
  6. public class SysRole {
  7. @Id
  8. @GeneratedValue
  9. private Long id;
  10. private String name;
  11. public Long getId() {
  12. return id;
  13. }
  14. public void setId(Long id) {
  15. this.id = id;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. }
  24. package com.springsecutity.secutity.entity;
  25. import org.springframework.security.core.GrantedAuthority;
  26. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  27. import org.springframework.security.core.userdetails.UserDetails;
  28. import javax.persistence.*;
  29. import java.util.ArrayList;
  30. import java.util.Collection;
  31. import java.util.List;
  32. /**
  33. * @Author: shanggq
  34. * @date: 2018/12/12
  35. * UserDetails 将当前用户交给 spring Security 去管理
  36. */
  37. @Entity
  38. public class SysUser implements UserDetails {
  39. @Id
  40. @GeneratedValue
  41. private Long id;
  42. private String username;
  43. private String password;
  44. // CascadeType.PERSIST 用于级联保存设置
  45. // FetchType.EAGER 在级联保存的时候需要首先获取数据
  46. @ManyToMany(cascade = {CascadeType.PERSIST}, fetch = FetchType.EAGER)
  47. private List<SysRole> roles;
  48. @Override
  49. public Collection<? extends GrantedAuthority> getAuthorities() {
  50. List<GrantedAuthority> auths = new ArrayList<>();
  51. List<SysRole> roles = this.getRoles();
  52. for (SysRole role : roles) {
  53. auths.add(new SimpleGrantedAuthority(role.getName()));
  54. }
  55. return auths;
  56. }
  57. @Override
  58. public boolean isAccountNonExpired() {
  59. return true;
  60. }
  61. @Override
  62. public boolean isAccountNonLocked() {
  63. return true;
  64. }
  65. @Override
  66. public boolean isCredentialsNonExpired() {
  67. return true;
  68. }
  69. @Override
  70. public boolean isEnabled() {
  71. return true;
  72. }
  73. public Long getId() {
  74. return id;
  75. }
  76. public void setId(Long id) {
  77. this.id = id;
  78. }
  79. @Override
  80. public String getUsername() {
  81. return username;
  82. }
  83. public void setUsername(String username) {
  84. this.username = username;
  85. }
  86. @Override
  87. public String getPassword() {
  88. return password;
  89. }
  90. public void setPassword(String password) {
  91. this.password = password;
  92. }
  93. public List<SysRole> getRoles() {
  94. return roles;
  95. }
  96. public void setRoles(List<SysRole> roles) {
  97. this.roles = roles;
  98. }
  99. }

Msg用于传递数据,在页面进行数据访问显示

  1. package com.springsecutity.secutity.entity;
  2. /**
  3. * 用于传递用户的信息
  4. */
  5. public class Msg {
  6. private String title;
  7. private String content;
  8. private String etraInfo;
  9. public Msg(String title, String content, String etraInfo) {
  10. this.title = title;
  11. this.content = content;
  12. this.etraInfo = etraInfo;
  13. }
  14. public String getTitle() {
  15. return title;
  16. }
  17. public void setTitle(String title) {
  18. this.title = title;
  19. }
  20. public String getContent() {
  21. return content;
  22. }
  23. public void setContent(String content) {
  24. this.content = content;
  25. }
  26. public String getEtraInfo() {
  27. return etraInfo;
  28. }
  29. public void setEtraInfo(String etraInfo) {
  30. this.etraInfo = etraInfo;
  31. }
  32. }

MySecutityConfig 配置 核心配置

  1. package com.springsecutity.secutity.config;
  2. import com.springsecutity.secutity.service.CustomUserService;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  6. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  7. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  9. import org.springframework.security.core.userdetails.UserDetailsService;
  10. @Configuration
  11. @EnableGlobalMethodSecurity(prePostEnabled = true)
  12. public class MySecutityConfig extends WebSecurityConfigurerAdapter {
  13. @Bean
  14. public UserDetailsService customUserService() {
  15. return new CustomUserService();
  16. }
  17. /**
  18. * 用于设置用户登录成功和失败的页面,设置cookie的有效时间,设置私密
  19. *
  20. * @param http
  21. * @throws Exception
  22. */
  23. @Override
  24. protected void configure(HttpSecurity http) throws Exception {
  25. // http.formLogin() // 通过formLogin 方法定制登录操作
  26. // .loginPage("/login") //定制登录页面的访问地址
  27. // .defaultSuccessUrl(".index") // 指定登录成功之后转向的页面
  28. // .failureUrl("/login?error") // 指定登录失败之后转向的页面
  29. // .permitAll()
  30. // .and()
  31. // .rememberMe() // 用于开启cookie存储用户的信息
  32. // .tokenValiditySeconds(60 * 60 * 24) // 设置cookie存储用户的时间
  33. // .key("myKey") // 设置cookie中的私密
  34. // .and()
  35. // .logout() // 开启注销的行为
  36. // .logoutUrl("/custom-logout") // 注销的时候的url路径
  37. // .logoutSuccessUrl("/logout-success") // 注销成功之后跳转的页面
  38. // .permitAll();
  39. http.authorizeRequests()
  40. .antMatchers("/css/**", "/js/**", "/images/**", "/webjars/**", "**/favicon.ico", "/index")
  41. .permitAll()
  42. .anyRequest().authenticated()
  43. .and()
  44. .rememberMe()
  45. .tokenValiditySeconds(60 * 60)
  46. .key("mykey")
  47. .rememberMeParameter("remember-me")
  48. .rememberMeCookieName("workspace")
  49. .and()
  50. .formLogin()
  51. .loginPage("/login")
  52. // .successHandler(new ForwardAuthenticationSuccessHandler("/"))
  53. .defaultSuccessUrl("/")
  54. // 会去访问/login/error 的请求路径 ,如果是默认的/login?error 的路径 会默认有param 的属性
  55. .failureUrl("/login?error")
  56. .permitAll()
  57. .and()
  58. .logout()
  59. .permitAll();
  60. // 用于关闭跨域
  61. http.csrf().disable();
  62. }
  63. /**
  64. * 用于授权
  65. *
  66. * @param auth
  67. * @throws Exception
  68. */
  69. @Override
  70. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  71. auth.userDetailsService(customUserService()).passwordEncoder(new MyPasswordEncoder());
  72. }
  73. }

@EnableGlobalMethodSecurity(prePostEnabled = true) 该配置用于下面的密码的配置,需要使用到该配置

设置webMvc的配置 : 该配置主要是用于设置当访问/login的进行统一的处理,该配置也可以设置在上面的配置中

  1. package com.springsecutity.secutity.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
  4. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  5. @Configuration
  6. public class WebMvcConfig extends WebMvcConfigurerAdapter {
  7. @Override
  8. public void addViewControllers(ViewControllerRegistry registry) {
  9. registry.addViewController("/login").setViewName("login");
  10. }
  11. }

密码的配置:加该配置的原因是,在其余操作完成之后,进行用户的登录的时候,会发现后台出现密码为空的错误

  1. package com.springsecutity.secutity.config;
  2. import org.springframework.security.crypto.password.PasswordEncoder;
  3. public class MyPasswordEncoder implements PasswordEncoder {
  4. @Override
  5. public String encode(CharSequence charSequence) {
  6. return charSequence.toString();
  7. }
  8. @Override
  9. public boolean matches(CharSequence charSequence, String s) {
  10. return s.equals(charSequence.toString());
  11. }
  12. }

Controller层

  1. package com.springsecutity.secutity.controller;
  2. import com.springsecutity.secutity.entity.Msg;
  3. import com.springsecutity.secutity.entity.error;
  4. import org.springframework.security.access.prepost.PreAuthorize;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.ui.Model;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.ResponseBody;
  9. import java.util.HashMap;
  10. @Controller
  11. public class HomeController {
  12. @RequestMapping("/")
  13. public String index(Model model) {
  14. Msg msg = new Msg("测试标题", "测试内容", "额外信息,只对管理员展示,注销请求");
  15. model.addAttribute("msg", msg);
  16. return "index";
  17. }
  18. @RequestMapping("/login/error")
  19. public String error(Model model) {
  20. error error = new error("登录失败,请您重新登录", "");
  21. model.addAttribute("param", error);
  22. return "login";
  23. }
  24. @PreAuthorize("hasRole('ROLE_USER')" )
  25. @RequestMapping("/getName")
  26. @ResponseBody
  27. public String getName() {
  28. System.out.println(".....");
  29. return "asd";
  30. }
  31. }

service层

  1. package com.springsecutity.secutity.service;
  2. import com.springsecutity.secutity.dao.SysUserRepository;
  3. import com.springsecutity.secutity.entity.SysUser;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.security.core.userdetails.UserDetails;
  6. import org.springframework.security.core.userdetails.UserDetailsService;
  7. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  8. public class CustomUserService implements UserDetailsService {
  9. @Autowired
  10. private SysUserRepository sysUserRepository;
  11. @Override
  12. public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
  13. SysUser username = sysUserRepository.findByUsername(s);
  14. if (username == null) {
  15. throw new UsernameNotFoundException("用户查询失败 。。");
  16. }
  17. return username;
  18. }
  19. }

dao层,使用的hibernate进行数据的访问,如果使用mybatis,可直接将该接口修改为mybatis的接口

  1. package com.springsecutity.secutity.dao;
  2. import com.springsecutity.secutity.entity.SysUser;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. public interface SysUserRepository extends JpaRepository<SysUser, Long> {
  5. SysUser findByUsername(String username);
  6. }

login.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>登录页面</title>
  6. <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
  7. <style type="text/css">
  8. body {
  9. padding-top: 50px;
  10. }
  11. .starter-tempalte {
  12. padding: 40px 15px;
  13. text-align: center;
  14. }
  15. </style>
  16. </head>
  17. <body>
  18. <nav class="navber navbar-inverse navbar-fixed-top ">
  19. <div class="container">
  20. <a class="navbar-brand" href="#">Spring Security演示</a>
  21. </div>
  22. <div id="navbar" class="collapse navbar-collapse">
  23. <ul class="nav navbar-nav">
  24. <!--<li><a th:href="@{/}">首页</a></li>-->
  25. </ul>
  26. </div>
  27. </nav>
  28. <div class="starter-tempalte">
  29. <p th:if="${param.logout}" class="bg-waring">已成功注销</p>
  30. <p th:if="${param.error}" class="bg-waring">有错误,请重试</p>
  31. <h2>使用账号密码登录</h2>
  32. <form name="form" th:action="@{/login}" method="post">
  33. <div class="form-group">
  34. <label for="username">账号</label>
  35. <input type="text" class="form-control" name="username" id="username" value="" placeholder="账号">
  36. </div>
  37. <div class="form-group">
  38. <label for="password"></label>
  39. <input type="password" class="form-control" name="password" id="password" placeholder="密码">
  40. </div>
  41. <div>
  42. <!-- 是否记住我功能勾选框 -->
  43. <input id="remember-me" name="remember-me" type="checkbox"/>                
  44. <label for="remember-me">一周内记住我</label>
  45. </div>
  46. <input type="submit" id="login" value="Login" class="btn btn-primary">
  47. </form>
  48. </div>
  49. </body>
  50. </html>

其中param这个参数,是Security底层里面的数据,在核心配置的时候,如果登录错误会跳转到login?error中,这个是请求的Security底层的方法,如果不想使用该功能,可将登录失败的地址修改成自己的请求地址即可

index页面

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org"
  3. xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
  4. <!--xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4" 表示的是spring security 的标签支持-->
  5. <head>
  6. <meta charset="UTF-8">
  7. <!--sec:authentication="name" 获得当前用户名-->
  8. <title sec:authentication="name"></title>
  9. <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
  10. <script type="text/javascript" th:src="@{js/jquery-1.8.3.js}"></script>
  11. <style type="text/css">
  12. body {
  13. padding-top: 50px;
  14. }
  15. .starter-tempalte {
  16. padding: 40px 15px;
  17. text-align: center;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <nav class="navber navbar-inverse navbar-fixed-top ">
  23. <div class="container">
  24. <a class="navbar-brand" href="#">Spring Security演示</a>
  25. </div>
  26. <div id="navbar" class="collapse navbar-collapse">
  27. <ul class="nav navbar-nav">
  28. <li><a th:href="@{/}">首页</a></li>
  29. </ul>
  30. <ul class="nav navbar-nav">
  31. <li><a id="getname">用户名称</a></li>
  32. </ul>
  33. </div>
  34. </nav>
  35. <div class="container">
  36. <div class="starter-tempalte">
  37. <h1 th:text="${msg.title}"></h1>
  38. <p class="bg-primary" th:text="${msg.content}"></p>
  39. <div sec:authorize="hasRole('ROLE_ADMIN')">
  40. <p class="bg-info" th:text="${msg.etraInfo}"></p>
  41. </div>
  42. <div sec:authorize="hasRole('ROLE_USER')">
  43. <p class="bg-info" id="userRole">无更多信息</p>
  44. </div>
  45. <form th:action="@{/logout}" method="post">
  46. <input type="submit" class="btn btn-primary" value="注销">
  47. </form>
  48. </div>
  49. </div>
  50. </body>
  51. <script type="text/javascript">
  52. $("#getname").on("click", function () {
  53. $.get("http://localhost:5000/getName",function (data) {
  54. if(data == null && data == ""){
  55. $("#userRole").text("无更多信息");
  56. }else{
  57. $("#userRole").text(data);
  58. }
  59. });
  60. });
  61. </script>
  62. </html>

该页面中测试了权限设置,在controller中添加了getName的方法,并在上面添加了权限限制,但是对于没有权限的用户的提示方法我没有思路,有解决办法的大佬希望能给我指点一下

sql

  1. INSERT INTO SYS_USER (ID, username, PASSWORD) VALUES (1, 'wyf', 'wyf');
  2. INSERT INTO SYS_USER (ID, username, PASSWORD) VALUES (2, 'wisely', 'wisely');
  3. INSERT INTO SYS_ROLE (ID, name) VALUES (1, 'ROLE_ADMIN');
  4. INSERT INTO SYS_ROLE (ID, name) VALUES (2, 'ROLE_USER');
  5. INSERT INTO SYS_USER_ROLES (SYS_USER_ID, ROLES_ID) VALUES (1, 1);
  6. INSERT INTO SYS_USER_ROLES (SYS_USER_ID, ROLES_ID) VALUES (2, 2);

pom.xml 使用到的依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-cache</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-security</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-web</artifactId>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.mybatis.spring.boot</groupId>
  16. <artifactId>mybatis-spring-boot-starter</artifactId>
  17. <version>1.3.2</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>mysql</groupId>
  21. <artifactId>mysql-connector-java</artifactId>
  22. <scope>runtime</scope>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-test</artifactId>
  27. <scope>test</scope>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.security</groupId>
  31. <artifactId>spring-security-test</artifactId>
  32. <scope>test</scope>
  33. </dependency>
  34. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  38. <version>2.1.1.RELEASE</version>
  39. </dependency>
  40. <!-- thymeleaf 支持Security -->
  41. <dependency>
  42. <groupId>org.thymeleaf.extras</groupId>
  43. <artifactId>thymeleaf-extras-springsecurity4</artifactId>
  44. <version>3.0.4.RELEASE</version>
  45. </dependency>
  46. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
  47. <dependency>
  48. <groupId>org.springframework.boot</groupId>
  49. <artifactId>spring-boot-starter-data-jpa</artifactId>
  50. <version>2.1.1.RELEASE</version>
  51. </dependency>

application.yml

  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.jdbc.Driver
  4. url: jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=UTC
  5. username: root
  6. password: root
  7. thymeleaf:
  8. cache: false
  9. jpa:
  10. show-sql: true
  11. hibernate:
  12. ddl-auto: update
  13. logging:
  14. level:
  15. org:
  16. springframework:
  17. security: INFO
  18. server:
  19. port: 5000

本案例借鉴 《javaEE开发颠覆者》

发表评论

表情:
评论列表 (有 0 条评论,390人围观)

还没有评论,来说两句吧...

相关阅读