Spring boot与安全

一、Spring boot与安全

1、安全

​ 应用程序的两个主要区域是“认证”和“授权”(或者访问控制),这两个主要区域是安全的两个目标。 身份验证意味着确认您自己的身份,而授权意味着授予对系统的访问权限

  • 认证

    身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。系统确定您是否就是您所说的使用凭据。在公共和专用网络中,系统通过登录密码验证用户身份。身份验证通常通过用户名和密码完成,

  • 授权

    另一方面,授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。简单来说,授权决定了您访问系统的能力以及达到的程度。验证成功后,系统验证您的身份后,即可授权您访问系统资源。

2、Spring Security

​ Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型。他可以实现强大的web安全控制。对于安全控制,我们仅需引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。

  • WebSecurityConfigurerAdapter:自定义Security策略

​ 通过在配置类中继承该类重写configure(HttpSecurity http)方法来实现自定义策略

  • @EnableWebSecurity:开启WebSecurity模式

​ 在配置类上标注@EnableWebSecurity开启WebSecurity模式

3、 Springboot整合security

  1. 导入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  1. 登录和注册
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // .denyAll();    //拒绝访问
        // .authenticated();    //需认证通过
        // .permitAll();    //无条件允许访问
        //.hasRole("vip1"); //指定用户访问
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/*").hasRole("vip1")
                .antMatchers("/level2/*").hasRole("vip2")
                .antMatchers("/level3/*").hasRole("vip3");
        //登陆功能
			http.formLogin().loginPage("/login").usernameParameter("username").passwordParameter("password");
        //关闭防止网址攻击,这样注销功能才能正常使用
        http.csrf().disable();
        //注销功能,注册完成后跳转到index页面
        http.logout().logoutSuccessUrl("/index");

​ 此时除了主页,点击其他的页面都会自动跳转到security自动生成的登录页面,/login来到登陆页,重定向到/login?error表示登陆失败;除此之外也可以使用loginPage("")跳转到自己的登录页面。

http.logout()开启自动配置的注销功能,向/logout发送post请求表示注销,需要在欢迎页加上注销表单,默认注销后自动跳转到登录页面,若想改变转发路径,可以通过logoutSuccessUrl(url)设置路径

<form th:action="@{/logout}" method="post">
   <input type="submit" value="注销">
</form>
  1. 定义认证规则

​ 为了保证密码能安全存储,springboot内置PasswordEncoder对密码进行转码,默认密码编码器为DelegatingPasswordEncoder。在定义认证规则时,我们需要使用PasswordEncoder将密码转码,我们可以使用BCryptPasswordEncoder()来对用户密码进行加密。

	@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //.passwordEncoder(new BCryptPasswordEncoder() 密码加密方式
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).
                withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and().withUser("yue").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
                .and().withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
    }
  1. 自定义页面

引入命名空间

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
     xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

首页显示

<!--首页显示-->
<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" >
                        用户名:<span sec:authentication="name"> </span>
                    </a>
                </div>
                <!--已登录-->
                <div sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/logout}">
                        <i class="address card icon"></i> 注销
                    </a>
                </div>
            </div>
        </div>
    </div>

根据不同用户显示不同页面

<!--根据不同用户显示不同页面-->
<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>
  1. 记住我功能
//记住我
http.rememberMe().rememberMeParameter("remember");
<div class="field">
    <input type="checkbox" name="remember">记住我
</div>

​ 通过loginPage(url)设置登录页路径后,在定制的登录页发送post url即为登录请求,并设置表单的name属性都为对应值;

​ 通过勾选记住我,session退出后依然能通过cookie保存用户信息,下次免登陆。

更多spring-security参阅官方文档

4、Apache Shiro

​ Apache Shiro 是 Java 的⼀个安全(权限)框架。Shiro 可以轻松的完成:身份认证、授权、加密、会话管理等功能Shiro 可以⾮常容易的开发出⾜够好的应⽤,其不仅可以⽤在JavaSE 环境,也可以⽤在 JavaEE 环境。功能强⼤且易⽤,可以快速轻松地保护任何应⽤程序 ( 从最⼩的移动应⽤程序到最⼤的Web和企业应⽤程序)⽅便的与Web 集成和搭建缓存。

Apache Shiro官网

1. 功能简介:

  • Authentication:身份认证/登录,验证⽤户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的⽤户是否拥有某个权限;即判断⽤户是否能进⾏什么操作。如:验证某个⽤户是否拥有某个⻆⾊。或者细粒度的验证某个⽤户对某个资源是否具有某个权限;
  • Session Manager:会话管理,即⽤户登录后就是⼀次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,⽽不是明⽂存储;
  • Web Support:Web ⽀持,可以⾮常容易的集成到Web 环境;
  • Caching:缓存,⽐如⽤户登录后,其⽤户信息、拥有的⻆⾊/权限不必每次去查,这样可以提⾼效率;
  • Remember Me:记住我,这个是⾮常常⻅的功能,即⼀次登录后,下次再来的话可以⽴即知道你是哪个⽤户

2. 工作流程:

shiro 运⾏流程中,3个核⼼的组件:Subject、SecutiryManager、Realm

  • Subject
    安全校验中,最常⻅的问题是"当前⽤户是谁?" “当前⽤户是否有权做x事?”,所以考虑安全校验过程最⾃
    然的⽅式就是基于当前⽤户。Subject 代表了当前“⽤户”,
    应⽤代码直接交互的对象是 Subject,只要得到Subject对象⻢上可以做绝⼤多数的shiro操作。
    也就是说 Shiro 的对外API 核⼼就是 Subject。
    Subject 会将所有交互都会委托给 SecurityManager。

    Subject是安全管理中直接操作的对象

  • SecurityManager
    安全管理器;即所有与安全有关的操作都会与SecurityManager 交互;
    且其管理着所有 Subject;它是 Shiro的核⼼,
    它负责与 Shiro 的其他组件进⾏交互,它相当于 SpringMVC 中DispatcherServlet 的⻆⾊

  • Realm
    Shiro 从 Realm 获取安全数据(如⽤户、⻆⾊、权限),就是说SecurityManager 要验证⽤户身份,那么
    它需要从 Realm 获取相应的⽤户进⾏⽐较以确定⽤户身份是否合法;
    也需要从 Realm 得到⽤户相应的⻆⾊/权限进⾏验证⽤户是否能进⾏操作;
    可以把 Realm 看成 DAO,( 数据访问⼊⼝ )

3. shiro标签:

  • 身份认证
标签作用
<shiro:authenticated>已登录
<shiro:user>已登录或记住我
<shiro:guest>游客(未登录 且 未记住我)
<shiro:notauthenticated>未登录
<shiro:principal>获取⽤户身份信息
  • 角色校验
<shiro:hasAnyRoles name="admin,manager">是其中任何⼀种⻆⾊
<shiro:hasRole name="admin">是指定⻆⾊
<shiro:lacksRole name="admin">不是指定⻆⾊
  • 权限校验
<shiro:hasPermission name=“user:delete”>
有指定权限
<shiro:lacksPermission name=“user:delete”>
缺失指定权限
    
    
    <td>
        <a href="#" style="text-decoration:none">查看详情</a>
        <shiro:hasPermission name="user:delete">
            <a href="#" style="text-decoration: none">删除</a>
        </shiro:hasPermission>
        <shiro:lacksPermission name="user:delete">
            <a href="#" style="text-decoration: none" >⽆权删除</a>
        </shiro:lacksPermission>
    </td>

5、SpringBoot整合Shiro

  1. 导入依赖
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.2</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. 登录和注册

登录功能实现

//设置登陆页面
bean.setLoginUrl("/login");
<div shiro:notAuthenticated>
    <a th:href="@{/toLogin}">登陆</a>
</div>
	@PostMapping("/login")
    public String login(Model model,String username,String password){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装当前用户的数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            subject.login(token);//执行登陆方法。如果没有异常则登陆成功
            return "index";
        } catch (UnknownAccountException e) {//用户名不存在
            model.addAttribute("msg","用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

注册功能实现

<!--已登陆-->
<div shiro:Authenticated>
    <a th:href="@{/toLogout}">注销</a>
</div>
@GetMapping("/toLogout")
public String toLogout() {
    //获取当前用户
    Subject subject = SecurityUtils.getSubject();
    //移除当前用户的信息
    subject.logout();
    return "index";
}
  1. 定义认证规则
@Controller
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(defaultWebSecurityManager);
        /*
        * 添加shiro内置过滤器
        * anon:无需认证即可访问
        * authc:需要认证才能访问
        * perms:需要某个资源权限才能访问
        * role:需要某个角色才能访问
        * user:必须拥有“记住我”功能才能使用
        * */
        LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);
        //设置登陆页面
        bean.setLoginUrl("/login");
        //设置未授权的页面
        bean.setUnauthorizedUrl("/unauthorized");

        return bean;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        securityManager.setRealm(userRealm);
        return securityManager;
    }

    @Bean(name = "userRealm")
    public UserRealm getUserRealm(){
        return new UserRealm();
    }

    @Bean
    public ShiroDialect getShiroDialect() {
        return new ShiroDialect();
    }
}
public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //授权
        System.out.println("执行授权方法~");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //info.addStringPermission("user:add");   //经过授权方法,赋值user:add权力
        Subject subject = SecurityUtils.getSubject();
        //从subject中获取当前用户对象
        User tempUser = (User) subject.getPrincipal();
        //获取当前用户权限并赋值
        info.addStringPermission(tempUser.getPerms());
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //认证
        System.out.println("执行认证方法~");

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = userService.selectByName(token.getUsername());
        if (user == null){
            return null; //抛出异常
        }
        //密码认证shiro自动认证,将user对象放入subject中
        return new SimpleAuthenticationInfo(user,user.getPwd(),"");
    }
}
  1. 自定义页面
<html lang="en" xmlns:th="http://www.thymeleaf.org"
    xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<div shiro:notAuthenticated>
        <a th:href="@{/toLogin}">登陆</a>
    </div>
    <!--已登陆-->
    <div shiro:Authenticated>
        <a th:href="@{/toLogout}">注销</a>
    </div>

    </hr>
    <div shiro:hasPermission="user:add">
        <a th:href="@{user/add}">add</a>
    </div>
    </hr>
    <div shiro:hasPermission="user:update">
        <a th:href="@{user/update}">update</a>
    </div>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值