maven坐标:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
web委派:
<!--springsecurity web配置-->
<filter>
<!--
DelegatingFilterProxy用于整合第三方框架
整合Spring Security时过滤器的名称必须为springSecurityFilterChain,
否则会抛出NoSuchBeanDefinitionException异常
-->
<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>
配置文件:
<?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">
<!--配置不进行权限校验的目录-->
<!--<security:http security="none" pattern="/pages/**"/>-->
<!--配置可以访问登录界面-->
<security:http security="none" pattern="/login.html"/>
<!--
http:用于定义相关的权限控制
auto-config: 是否开启自动配置,例如填写true会自动给配置一个登陆界面
设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等
设置为false时需要显示提供登录表单配置,否则会报错
user-expressions:是否使用表达式,用于指定intercept-url中的access属性是否使用表达式
-->
<security:http auto-config="true" use-expressions="true">
<!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问,固定写法-->
<security:headers>
<security:frame-options policy="SAMEORIGIN"></security:frame-options>
</security:headers>
<!--
intercept-url:定义一个拦截规则
pattern:对哪些的URL进行拦截 /** 代表拦截所有目录下的所有URL
access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的劫色列表,
请求的用户只需拥有其中的一个角色就能成功访问对应的URL
其中ROLE_ADMIN是一个字符串 不代表任何含义
如果上方的user-expressions配置为false 则不需要写hasRole,直接写ROLE_ADMIN就可以
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
-->
<!--只要认证通过就可以访问-->
<security:intercept-url pattern="/pages/a.html" access="isAuthenticated()"/>
<!--拥有permission权限就可以访问-->
<security:intercept-url pattern="/pages/b.html" access="hasAnyAuthority('permission_A')"/>
<security:intercept-url pattern="/pages/d.html" access="hasAnyAuthority('permission_B')"/>
<!--拥有ROLE_ROOT角色就可以访问-->
<security:intercept-url pattern="/pages/c.html" access="hasRole('ROLE_ROOT')"/>
<!--拥有ROLE_ADMIN角色就可以访问d.html页面,
注意:此处虽然写的是ADMIN角色,框架会自动加上前缀ROLE_-->
<security:intercept-url pattern="/index.html" access="hasRole('ADMIN')" />
<!--如果我们要使用自己指定的页面作为登录页面,必须配置登陆表单,-->
<!--
login-page:指定登陆页面访问URL
username-parameter:登陆时提交的用户名的参数名称
password-parameter:登陆时提交的密码的参数名称
login-processing-url:登录页面表单提交的action地址路径(后台处理,登陆请求的路径,由框架自己提供)
default-target-url:登陆成功后跳转的页面
authentication-failure-forward-url:登陆失败跳转的页面
-->
<security:form-login login-page="/login.html"
username-parameter="username"
password-parameter="password"
login-processing-url="/login.do"
default-target-url="/index.html"
authentication-failure-forward-url="/login.html"
/>
<!--
csrf:对应CsrfFilter过滤器
disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403) true则代表关闭
-->
<security:csrf disabled="true"></security:csrf>
<!--
logout:退出登录
logout-url:退出登录操作对应的请求路径
logout-success-url:退出登录后的跳转页面
-->
<security:logout logout-url="/logout.do"
logout-success-url="/login.html" invalidate-session="true"/>
<!---->
<!-- Session管理 -->
<!-- invalid-session-url Session失效后跳转的界面,该页面不受security的控制
在error-if-maximum-exceeded设置true,且超出登陆次数的时候,则会跳转到此页面
session-fixation-protection是session攻击保护的策略
migrateSession:这是默认值。其表示在用户登录后将新建一个session,同时将原session中的attribute都copy到新的session中。
none:表示继续使用原来的session。
newSession:表示重新创建一个新的session,但是不copy原session拥有的attribute。
-->
<security:session-management invalid-session-url="/index.jsp"
session-fixation-protection="migrateSession">
<!--
当同一用户同时存在的已经通过认证的session数量超过了max-sessions所指定的值时,Spring Security的默认策略是将先前的设为无效。
如果要限制用户再次登录可以设置concurrency-control的error-if-maximum-exceeded的值为true。
-->
<security:concurrency-control error-if-maximum-exceeded="false" max-sessions="1"
expired-url="/login.html" />
</security:session-management>
</security:http>
<!--
authentication-manager:认证管理器,用于处理认证操作
-->
<security:authentication-manager>
<!--
authentication-provider:认证提供者,执行具体的认证逻辑
-->
<security:authentication-provider user-service-ref="userPassword">
<!--
user-service:用于获取用户信息,
提供给authentication-provider进行认证
<security:user-service>
user:定义用户信息,
可以指定用户名 密码 角色 ,后期可以改为从数据库查询的用户信息
authorities:表示当前的用户名为admin 密码为 admin
然后内容填写给这个用户分配的一个角色
{noop}:表示当前使用的密码为明文
<security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN"/>
</security:user-service>-->
<security:password-encoder ref="bCryptPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<bean id="userPassword" class="com.items.serviceimpl.UserPassword2"/>
<!--配置密码加密对象-->
<bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<!--开启spring注解-->
<context:annotation-config></context:annotation-config>
</beans>
配置后,实现UserDetailsService接口,进行登陆配置:
public class UserPassword2 implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
private Map<String,User> map = new HashMap();
private void init(){
User user1 = new User();
user1.setUsername("admin");
user1.setPassword(bCryptPasswordEncoder.encode("admin"));
User user2 = new User();
user2.setUsername("root");
user2.setPassword(bCryptPasswordEncoder.encode("1234"));
map.put(user1.getUsername(),user1);
map.put(user2.getUsername(),user2);
}
//上方为模仿数据库,真实开发不需要配置上方的代码
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
init();
System.out.println(username);
//根据username获取数据库中的用户
User user = map.get(username);
if(user == null){
//用户名不存在的时候
return null;
}
String password =user.getPassword();//noop代表明文
System.out.println(password);
//将用户的信息返回给框架
//框架会进行密码比对(页面提交的密码和数据库的密码)
List<GrantedAuthority> list = new ArrayList<>();
//为当前用户授权
if(username.equals("admin")){
list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
list.add(new SimpleGrantedAuthority("permission_A"));
}
if(username.equals("root")){
list.add(new SimpleGrantedAuthority("permission_B"));
list.add(new SimpleGrantedAuthority("ROLE_ROOT"));
}
/*springsecurity提供的user*/
org.springframework.security.core.userdetails.User security =
new org.springframework.security.core.userdetails.User(username, password, list);
return security;
}
}
注解:(可以控制类中方法的权限)
使用注解的时候首先开启注解
然后开启springsecurity的注解支持
<!--开启包扫描和mvc注解,与上方的spring注解开启一个就可以-->
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="com.items.controller"></context:component-scan>
<!--开启注解方式权限控制-->
<security:global-method-security pre-post-annotations="enabled" />
然后在类中添加注解:
@PreAuthorize("hasAuthority('add')")//表示用户必须拥有add权限才能调用当前方法
前端VUE权限不足给予提示方法:(固定写法)
//权限不足提示
showMessage(r){
if(r == 'Error: Request failed with status code 403'){
//权限不足
this.$message.error('无访问权限');
return;
}else{
this.$message.error('未知错误');
return;
}
},
使用户名动态显示:
在前端页面发送Ajax请求,然后再服务端获取username
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getUsername")
public Result getUsername(){
//获取security中的User
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//获取user中的username
String username = user.getUsername();
if(username != null){
return new Result(true,"获取用户名成功",username);
}
return new Result(false,"获取用户名失败");
}