Spring Security

Spring Security

  • Web开发中,安全First
  • 非功能需求(没它也能跑)
  • 应在设计之初考虑

依赖

<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- Thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

环境搭建

编写路由Controller,用于页面跳转

@Controller
public class RouterController {
    @RequestMapping({"/", "/index"})
    public String index() {
        return "index";
    }

    @RequestMapping("/toLogin")
    public String toLogin() {
        return "views/login";
    }

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id) {
        return "views/level1/" + id;
    }

    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id) {
        return "views/level2/" + id;
    }

    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id) {
        return "views/level3/" + id;
    }
}

用户认证和授权

编写Security的config类处理认证和授权

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // 授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 首页所有人可以访问, 功能页只有对应有权限的人才能看
        // 请求授权的规则
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        // 没有权限默认到登录页
        http.formLogin();
    }

    // 认证
    // 登录成功但认证失败, 缺少密码编码: PasswordEncoder
    // SpringSecurity 有许多加密方式
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 正常是从数据库读
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("lct").password(new BCryptPasswordEncoder().encode("1")).roles("vip1", "vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("1")).roles("vip1", "vip2", "vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("1")).roles("vip1");
    }
}

注销

在授权位置添加注销支持

// 授权
@Override
protected void configure(HttpSecurity http) throws Exception {
    // ...

    // 开启了注销功能
    // 默认会走"/logout"请求
    http.csrf().disable(); // 关闭后可通过Get方式请求(有时需要, 比如说注销突然404, 则大概率需要添加)
    http.logout().logoutSuccessUrl("/");
}

前端写一个注销请求的按钮

<!-- 如果已登录, 显示注销按钮 -->
<a class="item" th:href="@{/logout}">
    <i class="sign-out icon"></i> 注销
</a>

权限控制

添加依赖

<!-- Spring Security & Thymeleaf -->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>

index.html添加命名空间

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"

登录与否显示对应按钮

<!--semantic-ui-->
<link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">

<!--登录注销-->
<div class="right menu">
    <div sec:authorize="!isAuthenticated()">
        <!-- 如果未登录, 显示登录按钮 -->
        <a class="item" th:href="@{/login}">
            <i class="address card icon"></i> 登录
        </a>
    </div>
    <div sec:authorize="isAuthenticated()">
        <a class="item">
            用户名: <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>

根据身份显示可进入的页面(level1,其他一样)

<!-- 菜单动态实现 -->
<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>

Remember Me

在授权位置添加记住我支持

// 授权
@Override
protected void configure(HttpSecurity http) throws Exception {
    // ...

    // 开启记住我功能, 默认保存2周
    http.rememberMe();
}
img

自定义

配置

// 自定义接收前端的参数
http.rememberMe().rememberMeParameter("remember");

前端参数

<input type="checkbox" name="remember">Remember Me

首页定制

配置自定义的首页

// 授权
@Override
protected void configure(HttpSecurity http) throws Exception {
    // ...

    http.formLogin()
            .loginPage("/toLogin")
            .usernameParameter("username")
            .passwordParameter("password")
            .loginProcessingUrl("/login");

    // ...
}

前端传来的参数

<div class="ui placeholder segment">
    <div class="ui column very relaxed stackable grid">
        <div class="column">
            <div class="ui form">
                <form th:action="@{/login}" method="post">
                    <div class="field">
                        <label>Username</label>
                        <div class="ui left icon input">
                            <input type="text" placeholder="Username" name="username">
                            <i class="user icon"></i>
                        </div>
                    </div>
                    <div class="field">
                        <label>Password</label>
                        <div class="ui left icon input">
                            <input type="password" name="password">
                            <i class="lock icon"></i>
                        </div>
                    </div>
                    <div class="field">
                        <label>
                            <input type="checkbox" name="remember">
                        </label>Remember Me
                    </div>
                    <input type="submit" class="ui blue submit button"/>
                </form>
            </div>
        </div>
    </div>
</div>
posted @   James-Allen  阅读(15)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示