Spring Security入门(基于SSM环境配置)

Stella981
• 阅读 875

一、前期准备

  • 配置SSM环境
二、不使用数据库进行权限控制

配置好SSM环境以后,配置SpringSecurity环境

  1. 添加security依赖

       <dependency>     <groupId>org.springframework.security</groupId>     <artifactId>spring-security-config</artifactId>     <version>4.1.0.RELEASE</version>   </dependency>   <dependency>     <groupId>org.springframework.security</groupId>     <artifactId>spring-security-web</artifactId>     <version>4.1.0.RELEASE</version>   </dependency>
    
  2. 在服务器启动该的时候读取springSecurity配置文件

    实现方法,通过application域对象实现,和整合springmybatis的方法相同

    <listener>   <listener-class>       org.springframework.web.context.ContextLoaderListener   </listener-class></listener><context-param>   <param-name>contextConfigLocation</param-name>   <param-value>     classpath:springSecurity.xml   </param-value></context-param><filter>   <filter-name>springSecurityFilterChain</filter-name>   <filter-class>       org.springframework.web.filter.DelegatingFilterProxy   </filter-class></filter><filter-mapping>   <filter-name>springSecurityFilterChain</filter-name>   <url-pattern>/*</url-pattern></filter-mapping>
    
  • 通过spring提供的监听器加载security配置文件。

  • 使用过滤器链拦截所有的资源,来实现对资源的权限控制

  1. 书写springSecurity配置文件

    security:http        <security:intercept-url pattern="add" access="hasAuthority('ROLE_USER')" />        <security:intercept-url pattern="index.jsp" access="permitAll()"/>        <security:intercept-url pattern="/login" access="permitAll()"/>        <security:intercept-url pattern="/*" access="isFullyAuthenticated()"/>        <security:form-login login-page="/login" login-processing-url="/login"            authentication-failure-handler-ref="failureHandler"             authentication-success-handler-ref="successHandler">                <security:csrf disabled="true">security:authentication-manager    security:authentication-provider        security:user-service            <security:user                         name="username"                         password="username"                          authorities="ROLE_USER">                            

  • security:http配置权限拦截的方式是基于HTTP

  • 资源拦截方式,有两种

  • security:form-login基于表单(常用)

  • `security`默认提供一个登陆界面,可以自定义

  • `login-page`指定登陆界面(注:用户名的`name`属性必须为`username`,密码的`name`属性必须为`password`。这是`security`判断用户输入是否正确的标准)

  • `login-processing-url`指定登陆界面的表单的提交路径

  • `authentication-failure-handler-ref`引用一个密码错误以后的处理方式(上面的使用了`bean`引用)

  • `authentication-success-handler-ref`应用一个成功以后的处理方式

  • security:http-basic基本的验证方式(不常用)

  • secutity:authentication-manager具体的权限管理配置

  • security:intercept-url配置需要拦截的资源

  • access配置可以访问的权限(取值参考:security官方文档)

  • pattern配置需要拦截的资源(上面的资源使用MVC控制)

  • security:csrf一种浏览器的防护机制,后期文章会详细说明

  • security:authentication-provider具体的实现权限控制

  • security:user配置一个具体的用户

  • authorities配置当前用户所具有的权限,在intercept-url中使用

  1. 配置成功和失败的处理器

    通过实现AuthenticationSuccessHandler接口和AuthenticationFailureHandler实现

    public class FailureHandler implements AuthenticationFailureHandler {   @Override   public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)        throws IOException, ServletException {      response.getWriter().write(WriteStatusJson.loginStatus("status","Failure"));   }}public class SuccessHandler implements AuthenticationSuccessHandler {   @Override   public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {       response.getWriter().write(WriteStatusJson.loginStatus("status","success"));   }}
    
  • WriteStatusJson这个类是笔者自定义的一个回状态的工具类,具体实现如下

         public class WriteStatusJson {         /**          * 返回登陆状态信息          * @param attritute 登陆的状态          * @param value  登陆的成功过或者失败的返回值          * @param   根据每一次状态返回的值而定          * @return {String} 返回一个json字符串          * @throws JsonProcessingException          */         public static  String loginStatus(String attritute , E value)          throws JsonProcessingException {             ObjectMapper objectMapper = new ObjectMapper();             Map<String,E> map = new HashMap<>();             map.put(attritute,value);             return objectMapper.writeValueAsString(map);         }     }

     - 主要功能,将需要返回的状态信息转换为字符串(字符串转换使用了Jackson

此时一个基本的权限功能已经结束。


三、通过数据库实现权限控制

存在的问题

  • 用户已经写死,需要增加用户只能通过修改xml文件。

解决问题的思路

  • 通过Java代码生成一个User并且赋予它一定的权限

  • 引用入一个接口UserDetailsSevrice重写里面的方法loadUserByUsername

  • 方法返回值是一个UserDetails类型,Spring提供了一个类User实现了UserDetails查看User类的源码

        private static final long serialVersionUID = 410L;//序列化    private String password;//密码    private final String username;//用户名    private final Set authorities;//权限的集合    private final boolean accountNonExpired;//权限是否过期    private final boolean accountNonLocked;//权限是否被锁定    private final boolean credentialsNonExpired;//凭据未过期    private final boolean enabled;//账户可以使用

  • 创建管理用户权限的类

    public class UserAuthent implements UserDetailsService {    @Override    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {        User user = new User("MakerStack","love", AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER,ROLE_ADMIN"));        return user;    }}

  • AuthorityUtils工具类给用户赋予权限,类似于xml中的authorities属性


存在的问题

  • 用户还是写死的,只能用过spring自带的User对象来赋值,不能连接数据库

解决思路

  • 上面提到spring自带的User通过实现了UserDetails接口来实现对用户权限的添加

  • 自定义User类实现UserDetails接口,创建操纵User类的持久层接口,获取数据库中的User对象**

具体实现

  1. 数据库设计(具体情况具体考虑)
  • 三个表:

  • 用户表。存放具体的用户

  • 角色表。存放对应的角色。(管理员,会员,普通用户)

  • 权限表。存放具体的权限。(增加,删除,修改,查询权限的控制)

  • 每一个用户可以有多个角色,一个角色也可以有多个权限

  • 用户和角色。多对多的关系

  • 角色和权限。多对多的关系

  1. 编写数据库表的ORM映射,编写持久层接口,服务层接口

  2. 创建实现UserDetailsService接口的类,实现方法

    User user = userService.findUserByUsername(username);if(user!=null){   List<Authority> authorities = userService.findAuthorityByUsername(username);   //需要对user的List<Authority>集合赋值   List<GrantedAuthority> grantedAuthorities = new ArrayList<>();   for (Authority authority : authorities) {       GrantedAuthority grantedAuthority =            new SimpleGrantedAuthority(authority.getTag());       grantedAuthorities.add(grantedAuthority);     }   user.setAuthorities(grantedAuthorities);}return user;
    
  • 方法loadUserByUsername方法的参数即为用户在表单中输入的用户名(后期会出一篇security执行流程的文章,可以关注一下)

  • 通过用户名获取对应的用户信息,判断用户是否存在,存在即获取其对应的权限信息;若不存在则直接返回

  • 实体类User实现了UserDetails接口,内部定义了一个存储用户权限的集合。现在需要做的就是将数据库中的权限信息添加到这个集合中。

  • 通过spring提供的接口GrantedAuthority来实现;通过其子类SimpleGrantedAuthority将数据库中的权限信息写入,赋值给GrantedAuthority类型,添加到一个集合中,将这个集合赋值给user类的权限集合

    数据库整合完成

需要注意的问题

  • 登陆界面的name属性必须保证,否则会出现loadUserByUsername方法获取不到参数的问题

  • 用户名为username

  • 密码为password

  • 否则security无法读取

  • 若有读者出现这个错误

  • Access denied for user 'root'@'localhost'(using password: YES)且你之前连接数据库是正确的,则检查你得数据库配置文件


四、密码加密

目前数据库中存放的密码均为明文传输,所以需要对密码进行加密,而security提供了为密码加密的算法

步骤

  1. 为数据库中的密码加密
  • 通过security提供的接口PasswordEncoder的实现类BCryptPasswordEncoder实现用户密码的加密和匹配

  • 接口PasswordEncoder中的方法

    String encode(CharSequence var1);boolean matches(CharSequence var1, String var2);
    
  • 实现加密

    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();       //哈希算法+变量String encode = passwordEncoder.encode("123456");User user = new User();user.setId(3);user.setPassword(encode);userService.updateUserPassword(user);
    
  1. 登陆时实现解密
  • 创建BCryptPasswordEncoder类的bean对象

  • 在标签中引用


喜欢可以点一个在看

本文分享自微信公众号 - MakerStack(MakerStack)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Aidan075 Aidan075
3年前
如何用python进行数据分析——00环境配置
↑一个宝藏公众号,长的好看的人都关注了 简单介绍一下Python吧Python是一种面向对象程序设计语言,由荷兰人吉多·范罗苏姆于1989年底发明。目前是最常用也是最热门的一门编程语言之一,应用非常广泛。(不是这个面对对象)为什么选择python呢?有人说python是万能的,除了生孩子不会,什么都会。有人说python是未来
Aidan075 Aidan075
3年前
如何用python进行数据分析——00环境配置
↑一个宝藏公众号,长的好看的人都关注了 简单介绍一下Python吧Python是一种面向对象程序设计语言,由荷兰人吉多·范罗苏姆于19
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这