Spring Security的使用

博主名取自《小羊肖恩》中的小羊肖恩,名字为:肖恩,音译为Sean,自己取的姓:阿奇,为符合我们的阅读习惯,连起来组成为ArchieSean。博主志在将博客打造成为个人线上的技术栈,方便自己也方便他人。如博客中有任何错误,请各位指出,谢谢大家。

我的个人小站

Spring Security的使用

使用数据库认证

  • 在Spring Security中如果想要使用数据进行认证操作,有很多种操作方式,这里我们介绍使
    用UserDetails、 UserDetailsService来完成操作。

  • UserDetails

public interface UserDetails extends Serializable {    
     Collection<? extends GrantedAuthority> getAuthorities();   
     String getPassword();       
    String getUsername();       
    boolean isAccountNonExpired();      
    boolean isAccountNonLocked();    
    boolean isCredentialsNonExpired();   
     boolean isEnabled(); 
}

**UserDetails是一个接口,我们可以认为UserDetails作用是于封装当前进行认证的用户信息,但由于其是一个 接口,所以我们可以对其进行实现,也可以使用Spring Security提供的一个UserDetails的实现类User来完成 操作 **

  • 以下是User类的部分代码
public class User implements UserDetails, CredentialsContainer {

       private String password;  
       private final String username;  
       private final Set<GrantedAuthority> authorities;  
       private final boolean accountNonExpired; //帐户是否过期   
       private final boolean accountNonLocked; //帐户是否锁定   
       private final boolean credentialsNonExpired; //认证是否过期  
       private final boolean enabled; //帐户是否可用

}
  • UserDetailsService
public interface UserDetailsService {        UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }

登录案例

  • 导入坐标
<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
  • web-xml的配置
<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的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- 配置不拦截的资源 -->
    <security:http pattern="/login.jsp" security="none"/>
    <security:http pattern="/failer.jsp" security="none"/>
    <security:http pattern="/css/**" security="none"/>
    <security:http pattern="/img/**" security="none"/>
    <security:http pattern="/plugins/**" security="none"/>

    <!--
    	配置具体的规则
    	auto-config="true"	不用自己编写登录的页面,框架提供默认登录页面
    	use-expressions="false"	是否使用SPEL表达式(没学习过)
    -->
    <security:http auto-config="true" use-expressions="false">
        <!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER的角色" -->
        <security:intercept-url pattern="/**" access="ROLE_user,ROLE_admin"/>

        <!-- 定义跳转的具体的页面 -->
        <security:form-login
                login-page="/login.jsp"
                login-processing-url="/login.do"
                default-target-url="/index.jsp"
                authentication-failure-url="/failer.jsp"
                authentication-success-forward-url="/pages/main.jsp"
        />

        <!-- 关闭跨域请求 -->
        <security:csrf disabled="true"/>

        <!-- 退出 -->
        <security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" />

    </security:http>

    <!-- 切换成数据库中的用户名和密码 -->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userService">
            <!-- 配置加密的方式 -->
<!--            <security:password-encoder ref="passwordEncoder"/>-->
        </security:authentication-provider>
    </security:authentication-manager>

    <!-- 配置加密类 -->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

    <!-- 提供了入门的方式,在内存中存入用户名和密码
    <security:authentication-manager>
    	<security:authentication-provider>
    		<security:user-service>
    			<security:user name="admin" password="{noop}admin" authorities="ROLE_USER"/>
    		</security:user-service>
    	</security:authentication-provider>
    </security:authentication-manager>
    -->

</beans>

  • service层
// 接口
package com.slxy.service;

import org.springframework.security.core.userdetails.UserDetailsService;

public interface IUserService extends UserDetailsService {

}
package com.slxy.service.impl;

import com.slxy.dao.IUserDao;
import com.slxy.domain.Role;
import com.slxy.domain.UserInfo;
import com.slxy.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
    @Autowired
    private IUserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = null;
        try {
            userInfo = userDao.findByUsername(username);
        } catch (Exception e) {
            e.printStackTrace();
        }
        List<SimpleGrantedAuthority> list = getauthorities(userInfo.getRoles());
        User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 1 ? true : false,
                true, true, true, list);
        return user;
    }

    public List<SimpleGrantedAuthority> getauthorities(List<Role> roles) {
        List<SimpleGrantedAuthority> list = new ArrayList<SimpleGrantedAuthority>();
        for (Role role : roles) {
            list.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
        }
        return list;
    }
}

密码加密实现

  • 在spring-security配置文件中配置加密类
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
    <security:authentication-provider user-service-ref="userService">
    <!-- 配置加密的方式 -->
    <security:password-encoder ref="passwordEncoder"/>
    </security:authentication-provider>
</security:authentication-manager>

 <!-- 配置加密类 -->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
    
  1. 使用
  @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
     /**
     * @return java.lang.String
     * @Description //用户注册
     * @Param [userInfo]
     **/

@RequestMapping("/save.do")
public String save(UserInfo userInfo) throws Exception {
    userInfo.setPassword(bCryptPasswordEncoder.encode(userInfo.getPassword())); //加密操作
    userservice.save(userInfo);
    return "redirect:findAll.do";
}

服务器端方法级权限控制

  • 在服务器端我们可以通过Spring security提供的注解对方法来进行权限控制。Spring Security在方法的权限控制上 支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要 单独通过global-method-security元素的对应属性进行启用

开启注解的使用

  • 配置文件
<security:global-method-security jsr250-annotations="enabled"/>
<security:global-method-security secured-annotations="enabled"/>
<security:global-method-security pre-post-annotations="disabled"/>
  • 注解开启
    @EnableGlobalMethodSecurity :Spring Security默认是禁用注解的,要想开启注解,需要在继承 WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解,并在该类中将 AuthenticationManager定义为Bean。

JSR-250注解

  • @RolesAllowed表示访问对应方法时所具有的角色。
// 导入坐标
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>jsr250-api</artifactId>
    <version>1.0</version>
</dependency>
  • 在spring-security.xml中开启jsr250的注解支持。
 示例:
 @RolesAllowed({"USER", "ADMIN"})  该方法只要具有"USER", "ADMIN"任意一种权限就可以访问。
* 这里可以省 略前缀ROLE_,实际的权限可能是ROLE_ADMIN 
  • @PermitAll表示允许所有的角色进行访问,也就是不进行权限控制。
  • @DenyAll是和PermitAll相反的,表示无论什么角色都不能访问。

@Secured注解

  • @Secured注解的默认状态为disabled
 示例:  
@Secured("ROLE_TELLER") 
public Account readAccount(Long id);       

和jsr250的区别:@Secured是spring-security本身提供的方法级权限控制;jsr250是需要额外导入坐标来使用的。@Secured注解在使用时,必须加上“ROLE_”前缀来使用,而jar250注解可以省略前缀。

支持表达式的注解

  • @PreAuthorize在方法调用之前,基于表达式的计算结果来限制对方法的访问。
 <!--开启表达式的权限控制-->
<security:global-method-security pre-post-annotations="enabled"/>
示例: 
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
 void changePassword(@P("userId") long userId ){  }
  这里表示在changePassword方法执行之前,判断方法参数userId的值是否等于principal中保存的当前用户的 userId,或者当前用户是否具有ROLE_ADMIN权限,两种符合其一,就可以访问该方法。 
  • @PostAuthorize允许方法调用,但是如果表达式的计算结果是false,则会抛出一个安全性异常。
示例:
 @PostAuthorize User getUser("returnObject.userId == authentication.principal.userId or hasPermission(returnObject, 'ADMIN')"); 
  • @PostFilter允许方法调用,但必须按照表达式来过滤方法的结果。
  • @PreFilter允许方法调用,但必须在进入方法之前过滤输入值。

页面端权限控制

  • 在jsp页面中使用spring-security的权限控制。
  • 导入坐标
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>${spring.security.version}</version>
</dependency>
  • 页面导入
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

常用标签

  • authentication :代表当前认证对象,也可以获取信息。
<security:authentication property="" htmlEscape="" scope="" var=""/> 
1.  property: 只允许指定Authentication所拥有的属性,可以进行属性的级联获取,如“principle.username”, 不允许直接通过方法进行调用.
2. htmlEscape:表示是否需要将html进行转义。默认为true
3. scope:与var属性一起使用,用于指定存放获取的结果的属性名的作用范围,默认pageContext。Jsp中拥 有的作用范围都进行进行指定
4. var: 用于指定一个属性名,这样当获取到了authentication的相关信息后会将其以var指定的属性名进行存 放,默认是存放在pageConext中
  • authorize: 用于判断权限,根据权限来显示相应的内容。
<security:authorize access="" method="" url="" var=""></security:authorize> 
1. access: 需要使用表达式来判断权限,当表达式的返回结果为true时表示拥有对应的权限 
2. method:method属性是配合url属性一起使用的,表示用户应当具有指定url指定method访问的权限, method的默认值为GET,可选值为http请求的7种方法 
3. url:url表示如果用户拥有访问指定url的权限即表示可以显示authorize标签包含的内容 
4. var:用于指定将权限鉴定的结果存放在pageContext的哪个属性中
  • accesscontrollist:用于鉴定ACL权限的。其一共定义了三个属性:hasPermission、domainObject和var, 其中前两个是必须指定的。
<security:accesscontrollist hasPermission="" domainObject="" var=""></security:accesscontrollist> 
1. hasPermission:hasPermission属性用于指定以逗号分隔的权限列表 
2. domainObject:domainObject用于指定对应的域对象 
3. var:var则是用以将鉴定的结果以指定的属性名存入pageContext中,以供同一页面的其它地方使用

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页

打赏作者

ArchieSean

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值