Spring Security 5.0.x ----springmvc学习笔记
一、环境配置
1.导入依赖
<properties>
<spring.security.version>5.0.5.RELEASE</spring.security.version>
</properties>
<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>
2.配置web.xml
注意filter和filter-mapping 以及servlet的顺序(在idea中会有放置提示)
filter-->filter-mapping-->listener-->servlet-->servlet-mapping
<!-- 整合第三方框架的过滤器--> <filter> <!-- 整合spring security时,此过滤器的名称固定springSecurityFilterChain--> <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>
3.Spring Security要求提供SpringSecurityUserService ,并且实现UserDetailService接口
这里的SpringSecurityUserService后面在xml中需要配置进去。我这里使用的Dubbo远程请求数据库获取用户信息。
3.1 UserDetails
UserDetails里面存储的是用户信息以及用户拥有的角色和权限信息
//权限和角色信息都将存储在这个集合里面
Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername();
3.2 GrantedAuthority(已授予的权限)
GrantedAuthority接口的实现类SimpleGrantedAuthority,在构建SimpleGrantedAuthority对象的时候,存放角色和权限的字符串,而且是需要带有前缀的字符串。
角色表

权限表

角色能不能不带"ROLE_"前缀?
Spring security在check权限的时候是比较的字符串信息,比如它有个表达式hasRole("ADMIN")。那它实际上查询的是用户权限集合中是否存在字符串"ROLE_ADMIN"。如果你从角色表中取出用户所拥有的角色时不加上"ROLE_"前缀,那验证的时候就匹配不上了。所以角色信息存储的时候可以没有"ROLE_"前缀,但是包装成GrantedAuthority对象的时候必须要有。
具体的解释请参考https://www.cnblogs.com/longfurcat/p/9417422.html
@Component
public class SpringSecurityUserService implements UserDetailsService {
@Reference //注意:此处要通过dubbo远程调用用户服务
private UserService userService;
/**
*根据用户名获取用户信息
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user=userService.findByUserName(username);
if(user==null){
return null;
}
// springsecurity将所有的角色和权限都存储在GrantedAuthority中
// ,比对字符串,所以权限角色的字符串应该必须带有Role或者代表权限的前缀
// GrantedAuthority已授予的权限
ArrayList<GrantedAuthority> list = new ArrayList<>();
Set<Role> roles = user.getRoles();
for (Role role : roles) {
// 授予角色 带前缀的字符串集合
list.add(new SimpleGrantedAuthority(role.getKeyword()));
// 授予权限
Set<Permission> permissions = role.getPermissions();
for (Permission permission : permissions) {
list.add(new SimpleGrantedAuthority(permission.getKeyword()));
}
}
UserDetails userDetails = new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(), list);
return userDetails;
}
}
4. spring-security.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="it.gzh.controller"/>
<!--
http:用于定义相关权限控制
指定哪些资源不需要进行权限校验,可以使用通配符
-->
<security:http security="none" pattern="/js/**" />
<security:http security="none" pattern="/css/**" />
<security:http security="none" pattern="/img/**" />
<security:http security="none" pattern="/plugins/**" />
<security:http security="none" pattern="/pages/login.html" />
<!-- <security:http security="none" pattern="/pages/main.html" />-->
<!--
http:用于定义相关权限控制
auto-config:是否自动配置
设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等
设置为false时需要显示提供登录表单配置,否则会报错
use-expressions:用于指定intercept-url中的access属性是否使用表达式
-->
<security:http auto-config="true" use-expressions="true">
<security:headers>
<!-- 设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
<security:frame-options policy="SAMEORIGIN"/>
</security:headers>
<!--
intercept-url:定义一个拦截规则
pattern:对哪些url进行权限控制
access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,请求的用户只需拥有其中的一个角色就能成功访问对应的URL
isAuthenticated():已经经过认证(不是匿名用户)
-->
<security:intercept-url pattern="/pages/**" access="isAuthenticated()"/>
<!--form‐login:定义表单登录信息-->
<security:form-login
login-page="/pages/login.html"
username-parameter="username"
password-parameter="password"
login-processing-url="/login.do"
default-target-url="/pages/main.html"
always-use-default-target="true"
authentication-failure-url="/pages/login.html"/>
<!-- 退出-->
<security:logout logout-url="/logout.do"
logout-success-url="/pages/login.html"
invalidate-session="true"/>
<!--
csrf:对应CsrfFilter过滤器
disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭
此项,
否则登录操作会被禁用(403)-->
<security:csrf disabled="true"/>
</security:http>
<!--配置密码加密对象-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<!--
authentication-manager:认证管理器,用于处理认证操作
-->
<security:authentication-manager>
<!--
authentication-provider:认证提供者,执行具体的认证逻辑
-->
<security:authentication-provider user-service-ref="springSecurityUserService">
<!--指定密码加密策略-->
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
<!--开启注解方式权限控制-->
<security:global-method-security pre-post-annotations="enabled" />
</beans>
在springmvc.xml中引入spring-security.xml文件
<import resource="spring-security.xml"/>
5. 注解使用权限控制
@PreAuthorize("hasAuthority('CHECKITEM_ADD')")//权限校验
6. 获取Spring Security上下文对象中存储的用户信息
try{
org.springframework.security.core.userdetails.User user =
(org.springframework.security.core.userdetails.User)
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,user.getUsername());
}catch (Exception e){
return new Result(false, MessageConstant.GET_USERNAME_FAIL);
}

浙公网安备 33010602011771号