初探SpringSecurity
一、导入核心jar包
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
二、在web.xml中添加核心过滤器
<!-- Spring Security 的过滤配置,表明请求需要经过这个类的过滤和判断 -->
<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>
三、新建权限的配置文件 applicationContext-security.xml
1.头文件如下
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
</beans:beans>
2.基本概念
权限=认证和授权
认证=校验用户名或者密码的有效性 密码是加密 密码 加密+加盐
授权=为授权通过的用户设置角色或者资源 ROLE_为前缀都是角色
权限最基本的表 4张表和5张表
3.开始配置applicationContext-security.xml
<http pattern="/login.jsp" security="none"/> #登录页面
<http pattern="/user/doValidateCode" security="none"/> #验证码的方法
<http pattern="/static/**" security="none"/> #所有的静态资源
#表示哪些资源不需要做拦截
4.规定所有的资源都需要具有USER角色才能访问 ROLE_USER
<http auto-config="true">
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
</http>
5.在http标签里面我们可以配置登录的信息
<http auto-config="true">
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<form-login
login-page="/login.jsp" #登录的页面
login-processing-url="/user/doLogin" #登录页面的请求地址
default-target-url="index.jsp" #默认的页面
username-parameter="username" #登录页面的用户名的参数
password-parameter="password" #登录页面的密码的参数
authentication-success-handler-ref="successHandler" #登录页面成功之后跳转的类
authentication-failure-url="/login.jsp" #失败之后跳转的页面
/>
#invalidate-session 清除session
#logout-url 退出的方法
<logout invalidate-session="true" logout-url="/user/doLogOut"></logout>
#在测试阶段 我们把它关闭 一般在真实下环境 我们要把防止CSRF跨站攻击给打开
<http:csrf disabled="true"></http:csrf>
#防止iframe攻击 一般把它关闭掉
<http:headers disabled="true" defaults-disabled="true"></http:headers>
#定义好/user/doLogOut地址 只要请求该地址 就自动跳转到首页 并且清空Session
<logout invalidate-session="true" logout-url="/user/doLogOut"></logout>
</http>
#认证是我们代码的核心 所有的认证都是由userService这个Bean来实现的
<beans:bean id="cryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder ref="cryptPasswordEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
配置好的applicationContext-security.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:http="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/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http pattern="/static/**" security="none"></http>
<http pattern="/login.jsp" security="none"></http>
<http auto-config="true" >
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<form-login
login-page="/login.jsp"
login-processing-url="/user/doLogin"
username-parameter="username"
password-parameter="password"
authentication-success-handler-ref="successHandler"
default-target-url="index.jsp"
authentication-failure-url="/login.jsp"
></form-login>
<!-- <http:access-denied-handler error-page="/error/403.jsp"></http:access-denied-handler>-->
<http:csrf disabled="true"></http:csrf>
<http:headers disabled="true" defaults-disabled="true"></http:headers>
<logout invalidate-session="true" logout-url="/user/doLogOut"></logout>
</http>
<beans:bean id="cryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder ref="cryptPasswordEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
</beans:beans>
四、Spring配置文件applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
</context:component-scan>
<bean id="annotationPropertyConfigurerRedis"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="1" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${db.dirverClass}"></property>
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="initialSize" value="1" />
<property name="minIdle" value="1" />
<property name="maxActive" value="20" />
<property name="maxWait" value="60000" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 1" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
<property name="filters" value="stat" />
</bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.blb.mapper"></property>
</bean>
</beans>
五、SpringMVC配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:http="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com" use-default-filters="true">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
</context:component-scan>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" ></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:annotation-driven/>
<http:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"></http:global-method-security>
<mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>
六、Mybatis配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
</configuration>
七、自定义登录成功后返回的对象
User对象自动存放到UsernamePasswordAuthenticationToken
package com.blb.vo;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
/**
* @author Administrator
* @date 2020/6/15
*/
public class LoginUserVO extends User {
private String welcome;
public LoginUserVO(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
public LoginUserVO(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
}
public LoginUserVO(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities,String welcome) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.welcome=welcome;
}
public String getWelcome() {
return welcome;
}
public void setWelcome(String welcome) {
this.welcome = welcome;
}
}
八、编写登录认证、授权的类
该类需要实现UserDetailsService
package com.blb.service;
import com.blb.vo.LoginUserVO;
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.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @author Administrator
* @date 2020/6/15
*/
@Service
public class UserService implements UserDetailsService {
//认证
//授权 角色 资源
//都放在一个方法里面去
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if(username.equals("zhangsan"))
{
List list=new ArrayList<>();
SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority("ROLE_USER");
//SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority("ROLE_ADMIN");
SimpleGrantedAuthority simpleGrantedAuthority2=new SimpleGrantedAuthority("USER_DROP");
list.add(simpleGrantedAuthority);
list.add(simpleGrantedAuthority2);
//用户可能不可用
//用户可能被锁定
//用户可能被禁用
// return new User(username,"123456",list);
return new LoginUserVO(username,"$2a$10$VFZXFyQShsKv/aAZxtnXlOKBg2Yczw.0CI5fwnc4QsiGWk8ryKahy",true,true,true,true,list);
}
return null;
}
}
九、编写认证成功后的类
package com.blb.handler;
import com.blb.vo.LoginUserVO;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Administrator
* @date 2020/6/15
*/
@Component
public class SuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
LoginUserVO userVO=(LoginUserVO) authentication.getPrincipal();
userVO.setWelcome("大家听明白没有");
httpServletRequest.setAttribute("menu","我是一个寂寞的菜单");
httpServletRequest.getRequestDispatcher("/index.jsp").forward(httpServletRequest,httpServletResponse);
}
}
十、准备好一个常量来判断登录后返回的信息
package com.blb.Contant;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
* @author Administrator
* @date 2020/6/15
*/
public class AuthContant {
public static final String InternalAuthenticationServiceException ="org.springframework.security.authentication.InternalAuthenticationServiceException: UserDetailsService returned null, which is an interface contract violation";
}
十一、在jsp页面判断
<c:if test="${sessionScope.SPRING_SECURITY_LAST_EXCEPTION eq AuthContant.InternalAuthenticationServiceException}">
用户名不存在
</c:if>
常见的错误异常如下
用户名不存在:InternalAuthenticationServiceException;
密码错误:BadCredentialException;
帐户被锁:LockedException;
帐户未启动:DisabledException;
密码过期:CredentialExpiredException;等等!
十二、jsp页面处理权限问题(选择性显示与隐藏页面的功能)
引入头文件
<%@taglib prefix="secuity" uri="http://www.springframework.org/security/tags" %>
判断是否有USER_ADD的权限
<security:authorize access="hasAuthority('USER_ADD')">
<button class="layui-btn" lay-event="isAll">全选</button>
</security:authorize>
判断是否ROLE_USER的角色
授权的时候要加上前缀
判断的时候不需要加前缀
<security:authorize access="hasRole('USER')">
<button class="layui-btn" lay-event="save">新增</button>
</security:authorize>
十三、编写带有权限的Controller方法
package com.blb.controller;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Administrator
* @date 2020/6/15
*/
@Controller
@RequestMapping("admin")
public class UserController {
@RequestMapping("add")
@PreAuthorize("hasAuthority('USER_ADD')")
public String add()
{
System.out.println("我是添加页面");
return "user/add";
}
}
@PreAuthorize("hasAuthority('USER_ADD')")使用该注解的前提是下图的配置必须在springmvc的配置文件中
<http:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"></http:global-method-security>
该注解其它的用法:
@PreAuthorize("hasRole('ROLE_ADMIN')") 必须有XXX角色才能访问
@PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
@PreAuthorize("#id<10") #id 表示方法的参数就是id
@PreAuthorize("principal.username.equals(#username)")
如果不想使用默认的注解方法,其它例如JSR250
https://www.cnblogs.com/fenglan/p/5913481.html
添加jar包
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
@RolesAllowed({"ROLE_USER", "ROLE_ADMIN"}) 必须要有XXX的角色
@PermitAll() 所有人都可以访问该方法
@DenyAll() 谁都不能访问该方法
@Secured("ROLE_ADMIN") 必须要有XXX角色才能访问
十四、在页面上,我们可以使用security:authentication 该标签就表示token,来获取token中的信息
<security:authentication property="principal.username"></security:authentication>