热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springsecurity登录和权限管理

springsecurityspringsecurity主要的两个功能是认证和授权认证的大概流程:UsernamepasswordAuthenticationFil

spring security

spring security 主要的两个功能是认证和授权
认证的大概流程:
Username password AuthenticationFilter(自定义usernamepassword拦截器)
UserDetailService (查询用户密码的service接口)
Userdetails (用户类接口)
AuthenticationProvide (为认证管理器AuthenticationManager 提供验证组件AuthenticationProvider)
授权的大概流程:
(extends)AbstractsecurityInterceptor +(implements)Filter(资源访问过滤器,拦截访问请求,封装成安全对象FilterInvocation,调用前两个实例进行鉴权)
FilterInvocationSecurityMetadataSource(自定义权限数据源,提供所有URL资源与对应角色权限的映射集合)
AccessDecisionManager (自定义鉴权管理器,根据URL资源权限和用户角色权限进行鉴权)

用户登陆
会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现,而且AuthenticationManager会调用ProviderManager来获取用户验证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等),如果验证通过后会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。
访问资源(即授权管理)
访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。

项目结构:
在这里插入图片描述
数据库设计:
在这里插入图片描述
model:
Permission

package com.example.arcgisdemo.model;import com.sun.javafx.beans.IDProperty;import javax.persistence.*;
import java.util.List;@Entity
@Table(name = "SYS_PERMISSION")
public class Permission {@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "ID")private int id;@Column(name = "NAME")private String name;@Column(name = "DESCRIPTION")private String description;@Column(name = "URL")private String url;@Column(name = "PID")private String pid;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getPid() {return pid;}public void setPid(String pid) {this.pid = pid;}}

User:
这里是在User中实现了UserDetails

package com.example.arcgisdemo.model;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;@Entity
@Table(name = "SYS_USER")
public class User implements UserDetails {&#64;Id&#64;GeneratedValue(strategy &#61; GenerationType.AUTO)&#64;Column(name &#61; "ID")private int id;&#64;Column(name &#61; "USERNAME")private String username;&#64;Column(name &#61; "PASSWORD")private String password;&#64;ManyToMany(fetch &#61; FetchType.EAGER)&#64;JoinTable(name &#61; "SYS_ROLE_USER",joinColumns &#61; {&#64;JoinColumn(name &#61; "SYS_USER_ID",referencedColumnName &#61; "ID")},inverseJoinColumns &#61; {&#64;JoinColumn(name &#61; "SYS_ROLE_ID",referencedColumnName &#61; "ID")})private List roles;&#64;Overridepublic Collection getAuthorities() {if (roles &#61;&#61; null || roles.size() <1) {return AuthorityUtils.commaSeparatedStringToAuthorityList("");}StringBuilder rolestring &#61; new StringBuilder();for (Role role : roles) {rolestring.append(role.getName()).append(",");}List authorityList &#61; AuthorityUtils.commaSeparatedStringToAuthorityList(rolestring.substring(0, rolestring.length() - 1));return authorityList;}public int getId() {return id;}public void setId(int id) {this.id &#61; id;}public String getUsername() {return username;}public void setUsername(String username) {this.username &#61; username;}public String getPassword() {return password;}public void setPassword(String password) {this.password &#61; password;}&#64;Overridepublic boolean isAccountNonExpired() {return true;}&#64;Overridepublic boolean isAccountNonLocked() {return true;}&#64;Overridepublic boolean isCredentialsNonExpired() {return true;}&#64;Overridepublic boolean isEnabled() {return true;}public List getRoles() {return roles;}public void setRoles(List roles) {this.roles &#61; roles;}}

Role

package com.example.arcgisdemo.model;import javax.persistence.*;
import java.util.List;&#64;Entity
&#64;Table(name &#61; "SYS_ROLE")
public class Role {&#64;Id&#64;GeneratedValue(strategy &#61; GenerationType.AUTO)&#64;Column(name &#61; "ID")private int id;&#64;Column(name &#61; "NAME")private String name;&#64;ManyToMany(fetch &#61; FetchType.EAGER)&#64;JoinTable(name &#61; "SYS_PERMISSION_ROLE",joinColumns &#61; {&#64;JoinColumn(name &#61; "ROLE_ID",referencedColumnName &#61; "ID")},inverseJoinColumns &#61; {&#64;JoinColumn(name &#61; "PERMISSION_ID",referencedColumnName &#61; "ID")})private List permissions;public int getId() {return id;}public void setId(int id) {this.id &#61; id;}public String getName() {return name;}public void setName(String name) {this.name &#61; name;}public List getPermissions() {return permissions;}public void setPermissions(List permissions) {this.permissions &#61; permissions;}
}

security:
WebSecurityConfig 配置

package com.example.arcgisdemo.security;import com.example.arcgisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;&#64;Configuration
&#64;EnableWebSecurity //注解开启Spring Security的功能
&#64;EnableGlobalMethodSecurity(prePostEnabled &#61; true) //开启Spring Security注解功能
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {&#64;Autowiredprivate UserService userService;&#64;Autowiredprivate SysFilterSecurityInterceptor sysFilterSecurityInterceptor;protected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
// auth.authenticationProvider(new SysDaoAuthenticationProvider());}protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/js/layui/**").permitAll() //定义不需要认证就可以访问的资源.anyRequest().authenticated().and().formLogin().loginPage("/login") //定义当需要用户登录时候&#xff0c;转到的登录页面.loginProcessingUrl("/login").defaultSuccessUrl("/", true).failureUrl("/login?error").permitAll().and().logout().logoutUrl("/logout")//退出登录后的默认Url是login.logoutSuccessUrl("/login").permitAll();//解决非thymeleaf的form表单提交被拦截问题http.csrf().disable();http.addFilter(customUsernamePasswordAuthenticationFilter());http.addFilterBefore(sysFilterSecurityInterceptor, FilterSecurityInterceptor.class).csrf().disable();http.headers().frameOptions().sameOrigin();}
/*,"https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Hydrography/Watershed173811/MapServer/1","https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Hydrography/Watershed173811/MapServer/0","http://192.168.101.4:8080/agapi/**"*/&#64;Beanpublic static NoOpPasswordEncoder passwordEncoder() {return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();}&#64;Beanpublic UserDetailsService systemUserService() {return new UserService();}&#64;Beanpublic SysUsernamePasswordF customUsernamePasswordAuthenticationFilter() throws Exception {SysUsernamePasswordF customUsernamePasswordAuthenticationFilter &#61; new SysUsernamePasswordF();customUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));customUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());customUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler());customUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));return customUsernamePasswordAuthenticationFilter;}
}

SysUsernamePasswordF

package com.example.arcgisdemo.security;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;public class SysUsernamePasswordF extends UsernamePasswordAuthenticationFilter {public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (!request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " &#43; request.getMethod());} else {String username &#61; this.obtainUsername(request);String password &#61; this.obtainPassword(request);if (username &#61;&#61; null) {username &#61; "";}else {}if (password &#61;&#61; null) {password &#61; "";}else {}username &#61; username.trim();UsernamePasswordAuthenticationToken authRequest &#61; new UsernamePasswordAuthenticationToken(username, password);this.setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}}
}

SysUserDetailsService

package com.example.arcgisdemo.security;import ch.qos.logback.core.joran.conditional.ElseAction;
import com.example.arcgisdemo.model.Permission;import com.example.arcgisdemo.model.User;
import com.example.arcgisdemo.service.PermissionService;
import com.example.arcgisdemo.service.SysUserService;
import com.example.arcgisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;import java.util.ArrayList;
import java.util.List;public class SysUserDetailsService implements UserDetailsService {&#64;Autowiredprivate SysUserService sysUserService;&#64;Autowiredprivate PermissionService permissionService;&#64;Overridepublic UserDetails loadUserByUsername(String username) {User user &#61; sysUserService.findByUserName(username);if (user !&#61; null) {List permissions &#61; permissionService.findById(user.getId());List grantedAuthorities &#61; new ArrayList<>();for (Permission permission : permissions) {if (permission !&#61; null && permission.getName() !&#61; null) {GrantedAuthority grantedAuthority &#61; new SimpleGrantedAuthority(permission.getName());//将此处权限信息添加到GrantedAuthority对象中&#xff0c;在后面进行全权限验证时会使用GrantedAuthoritygrantedAuthorities.add(grantedAuthority);}}return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);}else {throw new UsernameNotFoundException("do not exist");}}
}

SysInvocationSecurityMetadataSourceService

package com.example.arcgisdemo.security;import com.example.arcgisdemo.model.Permission;
import com.example.arcgisdemo.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import sun.security.krb5.Config;import javax.servlet.http.HttpServletRequest;
import java.util.*;&#64;Service
public class SysInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {&#64;Autowiredprivate PermissionService permissionService;private HashMap> map&#61;null;//加载权限表中所有权限public void loadResourceDefine(){map&#61;new HashMap<>();Collection array;ConfigAttribute cfg;List permissions&#61;permissionService.findAll();for (Permission permission:permissions){array&#61;new ArrayList<>();cfg&#61;new SecurityConfig(permission.getName());//此处指添加用户的名字&#xff0c;其实可以添加更多权限信息。例如请求方法到ConfigAttributr的集合中array.add(cfg);//用权限的getUrl。作为map的key。用ConfigAttribute的集合作为valuemap.put(permission.getUrl(),array);}}
//此方法是为了判定用户请求的url是否在权限表中&#xff0c;如果在权限表中&#xff0c;则返回给decide&#xff08;&#xff09;方法&#xff0c;
// 用来判断用户是否有此权限&#xff0c;如果不在权限表中则放行&#64;Overridepublic Collection getAttributes(Object object) throws IllegalArgumentException {if(map &#61;&#61;null)loadResourceDefine();//object中包含用户请求的request信息HttpServletRequest request&#61;((FilterInvocation)object).getHttpRequest();AntPathRequestMatcher matcher;String resUrl;for (Iterator iter&#61;map.keySet().iterator();iter.hasNext();){resUrl&#61;iter.next();matcher&#61;new AntPathRequestMatcher(resUrl);if (matcher.matches(request)){return map.get(resUrl);}}return null;}&#64;Overridepublic Collection getAllConfigAttributes() {return null;}&#64;Overridepublic boolean supports(Class aClass) {return true;}
}

SysFilterSecurityInterceptor

package com.example.arcgisdemo.security;import org.apache.catalina.connector.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;
import javax.servlet.*;import javax.servlet.*;
import java.io.IOException;
&#64;Service(value &#61; "sysFilterSecurityInterceptor")
public class SysFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {&#64;Autowired&#64;Qualifier(value &#61; "sysInvocationSecurityMetadataSourceService")private SysInvocationSecurityMetadataSourceService sysInvocationSecurityMetadataSourceService;&#64;Autowired&#64;Qualifier(value &#61; "sysAccessDecisionManager")public void setSysAccessDecisionManager(SysAccessDecisionManager sysAccessDecisionManager){super.setAccessDecisionManager(sysAccessDecisionManager);}&#64;Overridepublic void init(FilterConfig filterConfig) throws ServletException {}&#64;Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {FilterInvocation fi&#61;new FilterInvocation(servletRequest,servletResponse,filterChain);invoke(fi);}public void invoke(FilterInvocation fi)throws IOException,ServletException{//fi里面有一个被拦截的url//里面调用SysInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限//在调用SysAccessDecisionManager的decide方法来校验用户的权限是否足够InterceptorStatusToken token&#61;super.beforeInvocation(fi);try {//执行下一个拦截器fi.getChain().doFilter(fi.getRequest(),fi.getResponse());}finally {super.afterInvocation(token,null);}}&#64;Overridepublic void destroy() {}&#64;Overridepublic Class getSecureObjectClass() {return FilterInvocation.class;}&#64;Overridepublic SecurityMetadataSource obtainSecurityMetadataSource() {return this.sysInvocationSecurityMetadataSourceService;}
}

SysAccessDecisionManager

package com.example.arcgisdemo.security;import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;import java.util.Collection;
import java.util.Iterator;
&#64;Service(value &#61; "sysAccessDecisionManager")
public class SysAccessDecisionManager implements AccessDecisionManager {//decide方法是判定是否拥有权限的决策方法//authentication 是释SysUserDetailsService中循环添加到GrantedAuthority对象中的权限信息集合//object 包含客户端发起的请求的request信息。可转换为HttpServlerRequest request&#61;((FilterInvocation) object).getHttpRequest();//configAttributes 为InvocationSecurityMetadataSource的getAttributes&#xff08;Object&#xff09;这个方法返回的结果//此方法是为了判定用户请求的url&#xff0c;是否在权限表中&#xff0c;如果在权限表中&#xff0c;则返回给decide方法&#xff0c;//用来判定用户是否有此权限&#xff0c;如果不在权限表中则放行。&#64;Overridepublic void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {if (null&#61;&#61;configAttributes || configAttributes.size()<&#61;0){return;}ConfigAttribute configAttribute;String needRole;for (Iterator iter&#61;configAttributes.iterator();iter.hasNext();){configAttribute&#61;iter.next();needRole&#61;configAttribute.getAttribute();for (GrantedAuthority ga:authentication.getAuthorities()){if (needRole.trim().equals(ga.getAuthority())){return;}}}throw new AccessDeniedException("no right");}&#64;Overridepublic boolean supports(ConfigAttribute configAttribute) {return true;}&#64;Overridepublic boolean supports(Class aClass) {return true;}
}

Service:
PermissionService

package com.example.arcgisdemo.service;import com.example.arcgisdemo.dao.PermissionDao;
import com.example.arcgisdemo.model.Permission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;import java.util.List;&#64;Service(value &#61; "permissionService")
public class PermissionService {&#64;Autowired&#64;Qualifier(value &#61; "permissionDao")private PermissionDao permissionDao;public List findAll(){return permissionDao.findAll();}public List findById(int id){return permissionDao.findById(id);}
}

SysUserService

package com.example.arcgisdemo.service;import com.example.arcgisdemo.dao.UserMapper;
import com.example.arcgisdemo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import java.util.List;&#64;Service(value &#61; "sysUserService")
public class SysUserService {&#64;Autowired&#64;Qualifier(value &#61; "userMapper")private UserMapper userMapper;public User queryByUserName(String username) {return userMapper.queryByUsername(username);}public User findByUserName(String username){return userMapper.findByUsername(username);}
}

UserService

package com.example.arcgisdemo.service;import com.example.arcgisdemo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
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;
&#64;Service(value &#61; "userService")
public class UserService implements UserDetailsService {&#64;Autowiredprivate SysUserService systemUserService;&#64;Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {//根据用户名从数据库查询对应记录User user&#61;systemUserService.queryByUserName(s);if (user &#61;&#61;null){throw new UsernameNotFoundException("username is not exists");}System.out.println("username&#xff1a;"&#43;user.getUsername()&#43;",password:"&#43;user.getPassword());return user;}
}

dao:
PermissionDao

package com.example.arcgisdemo.dao;import com.example.arcgisdemo.model.Permission;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;import java.util.List;&#64;Repository(value &#61; "permissionDao")
public interface PermissionDao extends JpaRepository {List findAll();List findById(int id);
}

UserMapper

package com.example.arcgisdemo.dao;import com.example.arcgisdemo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;import java.util.List;&#64;Repository(value &#61; "userMapper")
public interface UserMapper extends JpaRepository {User queryByUsername(String username);User findByUsername(String username);
}

controller

package com.example.arcgisdemo.controller;import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;&#64;Controller
public class DemoController {&#64;RequestMapping("/login")public String login() {return "login";}&#64;RequestMapping("/")public String index1() {return "index-ui";}/*&#64;Secured({"ROLE_ADMIN"})*/&#64;RequestMapping("/user")public String user(){return "user";}&#64;RequestMapping("/map")public String map(){return "map";}
}

也可以在页面上设置权限&#xff0c;让没有权限的用户看不到该功能


在这里遇到个问题 刚开始的时候没有效果&#xff0c;经过找资料需要将spring 版本降到2.0.7以下
再加上&#xff1a;


pom.xml 需要配置secutiry扩展包

org.thymeleaf.extrasthymeleaf-extras-springsecurity43.0.2.RELEASE

参考文档&#xff1a;链接&#xff1a;https://www.jianshu.com/p/bcbbf16610fb


推荐阅读
author-avatar
happy柒月卍520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有