Spring Security 是 Spring 项目组中用来提供安全认证服务的框架。
网上相关的教程很多,也很详细。如:spring security——基本介绍(一)
这里就不过多赘述了,只写部分方法的使用及其注意点。

注:在 Security 中 方法大多为链式调用,且返回类型类名较长,故本篇文章将全程省略返回类型


一、部分方法介绍

配置类 SecurityConfig

1.1 注解、继承、重写的方法等

1.1.1 @EnableWebSecurity 注解

功能:表示该类启用了 Spring Security 的 Web 安全支持

1.1.2 configure(HttpSecurity http) 继承

功能
SecurityConfig类最基础的方法,定义了

  1. 请求授权的规则
  2. 表单验证__登录页的配置
  3. 注销、记住我等功能的配置

1.1.3 configure(AuthenticationManagerBuilder auth) 继承

功能:构建一个基于内存的身份验证器

  1. 该方法将身份信息存储在内存

configure(HttpSecurity http) 中使用以下内容

1.2 请求授权的规则

1.2.1 authorizeRequests()

功能:开启通过URL授权模式

  1. 必需的方法,写就对了
  2. 配合 antMatchers(String… antPatterns) 使用

1.2.2 antMatchers(String… antPatterns)

功能:指定需要授权的链接

1.2.3 permitAll()

功能:允许所有人通过调用该方法的请求

1.2.4 hasRole(String role)

功能指定允许通过调用该方法的请求的角色

  1. 该方法会自动向参数中的角色插入前缀 “ROLE“_
  2. 参数举例:USER, ADMIN
  3. 如果不需要前缀,可以使用 hasAuthority(String authority)

1.2.5 hasAuthority(String authority)

功能指定允许通过调用该方法的请求的角色

  1. 该方法与 hasRole(String role) 不同的是,它不会自动插入前缀 “ROLE“_
  2. 参数举例:ROLE_USER, ROLE_ADMIN

1.3 表单验证__登录页

1.3.1 formLogin()

功能:开启表单验证

  1. 如果没有使用 loginPage(String loginPage) 指定登录页,则会生成一个默认的登录表单

1.3.2 loginPage(String loginPage)

功能:指定登录页面

  1. 参数为 跳转到登录页面的请求
  2. 该方法只能出现一次

1.3.3 loginProcessingUrl(String loginProcessingUrl)

功能:指定登录页面的URL

  1. 该方法会覆盖 loginPage(String loginPage) 中指定的 url
  2. 该方法可以多次出现,即指定多个 url

1.3.4 usernameParameter(String usernameParameter)

功能:执行身份验证时查找用户名的HTTP参数。默认设置是“username”

  1. 与前端登录页填写用户名<input>name 属性一致

1.3.5 passwordParameter(String passwordParameter)

功能:执行身份验证时查找密码的HTTP参数。默认设置是“password”

  1. 与前端登录页填写密码<input>name 属性一致

1.4 注销

1.4.1 logout()

功能:开启注销功能

1.4.2 logoutSuccessUrl(String logoutSuccessUrl)

功能:注销成功后跳转到 对应请求(参数)

1.5 记住我

1.5.1 rememberMe()

功能:开启记住我功能

1.5.2 rememberMeParameter(String rememberMeParameter)

功能:用于表示在登录时记住用户的HTTP参数

  1. 与前端登录页记住我<input>name 属性一致

configure(AuthenticationManagerBuilder auth) 中使用以下内容

1.6 内存中的身份验证

1.6.1 inMemoryAuthentication()

功能:将内存中身份验证添加到 auth 中,并返回一个配置对象,以允许对内存中身份验证进行定制

1.6.2 passwordEncoder(PasswordEncoder passwordEncoder)

功能:指定加密方式

  1. 参数为一个对象。
  2. 该对象必须继承接口 org.springframework.security.crypto.password.PasswordEncoder

1.6.3 withUser(String username)

功能:添加用户至内存中

1.6.4 password(String password)

功能:指定添加的用户的密码

1.此项是必需的

1.6.5 roles(String… roles)

功能与注意点都与 hasRole(String role) 相同

1.6.6 authorities(String… authorities)

功能与注意点都与 hasAuthority(String authority) 相同


前端页面 Thymeaf

1.2.1 根据用户的角色动态显示不同的内容

在 div 中加入 sec:authorize="hasRole(String roleName)"

二、流程

2.1 自定义登录页方法执行流程

  1. 前端页面提交请求:/login
  2. 控制层接收请求:@RequestMapping(“/login”)
  3. 完成登录操作
  4. 进入Security配置类判断:
    1. 判断 loginPage(“/toLogin”) :参数不匹配 toLogin != login
    2. 判断 loginProcessingUrl(“/login”) :参数匹配,权限判断通过

三、代码

此处使用的是 狂神 的 Spring Security 教程中的演示代码,并以此为基础做了部分修改

依赖 pom.xml

  1. <dependencies>
  2. ...
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-security</artifactId>
  6. </dependency>
  7. ...
  8. </dependencies>

SecurityConfig.java

  1. package nuc.ss.config;
  2. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  3. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  4. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  6. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  7. // AOP:拦截器
  8. @EnableWebSecurity // 开启WebSecurity模式
  9. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  10. //链式编程
  11. //授权
  12. @Override
  13. protected void configure(HttpSecurity http) throws Exception {
  14. // 首页所有人都可以访问,功能也只有对应有权限的人才能访问到
  15. // 请求授权的规则
  16. http.authorizeRequests()
  17. .antMatchers("/").permitAll()
  18. .antMatchers("/level1/**").hasRole("vip1")
  19. .antMatchers("/level2/**").hasRole("vip2")
  20. .antMatchers("/level3/**").hasRole("vip3");
  21. // 没有权限默认会到登录页面,需要开启登录的页面
  22. // /login页面
  23. http.formLogin()
  24. .usernameParameter("username")
  25. .passwordParameter("password")
  26. .loginPage("/toLogin")
  27. .loginProcessingUrl("/login")
  28. .loginProcessingUrl("/toLogin");
  29. //注销,开启了注销功能,跳到首页
  30. http.logout().logoutSuccessUrl("/");
  31. // 防止网站工具:get,post
  32. http.csrf().disable();//关闭csrf功能,登录失败肯定存在的原因
  33. //开启记住我功能: cookie,默认保存两周,自定义接收前端的参数
  34. http.rememberMe().rememberMeParameter("remember");
  35. }
  36. // 认证,springboot 2.1.x 可以直接使用
  37. // 密码编码: PasswordEncoder
  38. // 在spring Secutiry 5.0+ 新增了很多加密方法
  39. @Override
  40. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  41. //这些数据正常应该中数据库中读
  42. auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
  43. .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
  44. .and()
  45. .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
  46. .and()
  47. .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
  48. }
  49. }

RouterController.java

  1. package nuc.ss.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.PathVariable;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. @Controller
  6. public class RouterController {
  7. @RequestMapping({"/","/index"})
  8. public String index() {
  9. return "index";
  10. }
  11. @RequestMapping({"/login","/toLogin"})
  12. public String toLogin() {
  13. return "views/login";
  14. }
  15. @RequestMapping("/level1/{id}")
  16. public String level1(@PathVariable("id") int id) {
  17. return "views/level1/" + id;
  18. }
  19. @RequestMapping("/level2/{id}")
  20. public String level2(@PathVariable("id") int id) {
  21. return "views/level2/" + id;
  22. }
  23. @RequestMapping("/level3/{id}")
  24. public String level3(@PathVariable("id") int id) {
  25. return "views/level3/" + id;
  26. }
  27. }

login.html 核心代码

  1. <form th:action="@{/toLogin}" method="post">
  2. <div class="field">
  3. <label>Username</label>
  4. <div class="ui left icon input">
  5. <input type="text" placeholder="Username" name="username">
  6. <i class="user icon"></i>
  7. </div>
  8. </div>
  9. <div class="field">
  10. <label>Password</label>
  11. <div class="ui left icon input">
  12. <input type="password" name="password">
  13. <i class="lock icon"></i>
  14. </div>
  15. </div>
  16. <div class="field">
  17. <input type="checkbox" name="remember"> 记住我
  18. </div>
  19. <input type="submit" class="ui blue submit button"/>
  20. </form>

index.html 核心代码

<div class="ui container">

    <div class="ui segment" id="index-header-nav" th:fragment="nav-menu">
        <div class="ui secondary menu">
            <a class="item"  th:href="@{/index}">首页</a>

            <!--登录注销-->
            <div class="right menu">

                <!--如果未登录-->
                <div sec:authorize="!isAuthenticated()">
                    <a class="item" th:href="@{/toLogin}">
                        <i class="address card icon"></i> 登录
                    </a>
                </div>

                <!--如果已登录-->
                <div sec:authorize="isAuthenticated()">
                    <a class="item">
                        <i class="address card icon"></i>
                        用户名:<span sec:authentication="principal.username"></span>
                        角色:<span sec:authentication="principal.authorities"></span>
                    </a>
                </div>

                <div sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/logout}">
                        <i class="sign-out  icon"></i> 注销
                    </a>
                </div>
            </div>
        </div>
    </div>

    <div class="ui segment" style="text-align: center">
        <h3>Spring Security Study by 秦疆</h3>
    </div>

    <div>
        <br>
        <div class="ui three column stackable grid">

            <!-- 菜单根据用户的角色动态的实现 -->
            <!-- sec:authorize="hasRole('vip1')" -->
            <div class="column" sec:authorize="hasRole('vip1')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 1</h5>
                            <hr>
                            <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                            <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                            <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip2')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 2</h5>
                            <hr>
                            <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                            <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                            <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip3')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 3</h5>
                            <hr>
                            <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                            <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                            <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

        </div>
    </div>

</div>

四、参考文献

4.1

4.2

4.3 IDEA中下下来的 Spring Security 源码中的方法注释