spring-boot用spring-sercurity很简单,只需要在maven引入相关依赖就好.
org.springframework.boot
spring-boot-starter-security
(一)简单示例
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}
密码加密类.provider验证的时候回用到.
@Component
public class AppAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("开始根据权限判断将要跳转的页面................");
String url=determineTargetUrl(authentication);
redirectStrategy.sendRedirect(request,response,url);
}
protected String determineTargetUrl(Authentication authentication){
String url="";
Collection extends GrantedAuthority> grantedAuthorities = authentication.getAuthorities();
List roles=new ArrayList<>();
for(GrantedAuthority grantedAuthority:grantedAuthorities){
roles.add(grantedAuthority.getAuthority());
}
//这里返回路径重定向,同样返回的是controller请求路径,并不是指静态文件的路径
if(roles.contains("ROLE_ADMIN")){
return "/admin";
}else if(roles.contains("ROLE_DBA")){
return "/dba";
}else if (roles.contains("ROLE_USER")){
return "/home";
}else {
return "/accessDenied";
}
}
}
验证成功跳转处理类.在验证成功后filter调用执行.
@Configuration
public class AppSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("开始认证角色..............");
//这里设置的角色 系统会自动加上role_前缀 既ROLE_ADMIN
auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder()).withUser("huangLei").password("a7633050").roles("ADMIN","DBA","USE");
auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder()).withUser("renling").password("huangl").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("开始配置权限...............3");
//过滤静态登录页面和静态资源,这里的/路径都是指的是controller请求路径并不是指静态页面路径
http.authorizeRequests()
.antMatchers("/login","/js/**").permitAll()
//配置各个访问url的权限
.antMatchers("/","/home").hasRole("USER")
.antMatchers("/admin/**").hasAnyRole("ADMIN","DBA")
.antMatchers("/dba/**").hasAnyRole("DBA")
//其他页面为需要登录之后
.anyRequest().authenticated()
//关闭防御跨站伪造请求,在使用thymeleaf中使用form表单发起请求,如果没有使用th:action则不会报错误,而使用action则会报错,关闭则都不会报错
.and().csrf().disable()
.formLogin()
//登录节点配置
.loginPage("/login")
//登录成功后负责跳转设置重定向路径的配置
.successHandler(authenticationSuccessHandler)
//失败后跳转的页面
.failureForwardUrl("/myError")
//配置登录参数
.usernameParameter("loginname").passwordParameter("password")
.and()
.logout().permitAll()
.and()
//配置由权限不足等引起的拒绝跳转的url
.exceptionHandling().accessDeniedPage("/accessDenied");
}
}
security最为重要的配置类.包括页面权限以及验证节点等的配置.各个配置的意义都有注释这里不再多说,需要强调的时在使用auth.inMemoryAuthentication()在内存中保存用户信息的时候系统会自动在权限前加上ROLE_前缀.
@Controller
public class SecurityController {
@RequestMapping("/")
public String index(ModelAndView modelAndView){
return "index";
}
@RequestMapping("/login")
public String login(ModelAndView modelAndView){
System.out.println("login");
return "login";
}
@RequestMapping("/ipLogin")
public String ipLogin(ModelAndView modelAndView){
System.out.println("ipLogin");
return "ipLogin";
}
@RequestMapping("/myError")
public String myError(ModelAndView modelAndView){
System.out.println("myError");
return "myError";
}
@RequestMapping("/admin")
public String admin(ModelAndView modelAndView){
System.out.println("admin");
modelAndView.addObject("user",getUserName());
modelAndView.addObject("roles",getAuthority());
System.out.println(getUserName());
return "admin";
}
@RequestMapping("/dba")
public String dba(ModelAndView modelAndView){
System.out.println("dba");
modelAndView.addObject("user",getUserName());
modelAndView.addObject("roles",getAuthority());
System.out.println(getUserName());
return "dba";
}
@RequestMapping("/home")
public String home(Model model){
//这里用modelAndView必须要给视图,不然前台无法获取model里的值
System.out.println("home");
model.addAttribute("user",getUserName());
model.addAttribute("role",getAuthority());
System.out.println(getUserName());
return "home";
}
@RequestMapping("/accessDenied")
public String accessDenied(ModelAndView modelAndView){
System.out.println("accessDenied");
modelAndView.addObject("user",getUserName());
modelAndView.addObject("roles",getAuthority());
return "accessDenied";
}
@RequestMapping("/logout")
public String logout(ModelAndView modelAndView, HttpServletRequest request, HttpServletResponse response){
System.out.println("logout");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication!=null){
new SecurityContextLogoutHandler().logout(request,response,authentication);
}
return "redirect:login";
}
public String getUserName(){
//通过获取securityContextHolder获取保存了用户信息的authentication实例对象
String userName= SecurityContextHolder.getContext().getAuthentication().getName();
return userName;
}
public String getAuthority(){
//获取权限
Collection extends GrantedAuthority> grantedAuthorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
ArrayList pers = new ArrayList<>();
for (GrantedAuthority grantedAuthority:grantedAuthorities){
pers.add(grantedAuthority.getAuthority());
}
return pers.toString();
}
}
页面跳转控制器,这里没有太多逻辑,仅仅是负责页面跳转.
(二)企业开发中常见的使用示例
@Service
public class SystemUserSerivce implements UserDetailsService {
@Autowired
private PermissionMapper permissionMapper;
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User myUser =userMapper.selectUserByUsername(s);
List permissions = permissionMapper.selectPermissionsByUserName(s);
List grantedAuthorities = new ArrayList<>();
for(Permission permission:permissions){
String permissionCode = permission.getPermissionCode();
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permissionCode);
grantedAuthorities.add(grantedAuthority);
}
//这里provider需要的是springSecurity的user对象
return new org.springframework.security.core.userdetails.User(s,myUser.getPassword(),grantedAuthorities);
}
}
userDetailService是被daoAuthenticationProvider调用用来加载用户及权限的接口,这里需要覆盖loadUserByUsername来从数据库加载用户信息.
@Configuration
public class AppSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private SystemUserSerivce systemUserSerivce;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationProvider authenticationProvider ;
@Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
@Bean
public PasswordEncoder passwordEncoder(){
//推荐使用该密码加密类
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
//是否隐藏没有找到用户的异常
daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
//设置userService实例
daoAuthenticationProvider.setUserDetailsService(systemUserSerivce);
//设置密码加密类
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
return daoAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//注册daoAutheticationProvider
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("开始配置权限...............4");
//过滤静态登录页面和静态资源,这里的/路径都是指的是controller请求路径并不是指静态页面路径
http.authorizeRequests()
.antMatchers("/login","/js/**").permitAll()
.antMatchers("/","/home").hasRole("USER")
.antMatchers("/admin/**").hasAnyRole("ADMIN","DBA")
.antMatchers("/dba/**").hasAnyRole("DBA")
.anyRequest().authenticated()
.and().csrf().disable()
.formLogin()
.loginPage("/login")
.successHandler(authenticationSuccessHandler)
.failureForwardUrl("/myError")
.usernameParameter("loginname").passwordParameter("password")
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/accessDenied");
}
}
另外,控制器类与successHandler与第一个示例相同,这里不做赘述.
这里与第一个示例不同的地方是我们需要从数据库中加载用户信息,所以我们选择实用daoAuthenticationProvider这个类,然后我们写一个类来继承负责加载数据库user信息的userDetailService的loadUserByUsername这个方法.这个示例是我们日常开发过程中实用的比较多的方式,在示例后面将会联系源码做重点分析
(三)依据ip作为登录验证参数的示例
这里是原文链接:
https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247483980&idx=1&sn=cb40ba4fea5cf100a98896d9a0404a43&chksm=fa497dfdcd3ef4ebdd162db2f674d882fd87d2648c775272a8af238c0500289d439d858804e5&scene=21#wechat_redirect
public class IpAuthenticationToken extends AbstractAuthenticationToken {
/**
* 对比UsernamePasswordAuthenticationToken 中的账号principal 密码credentials
*/
private String ip;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public IpAuthenticationToken(String ip){
super(null);
this.ip=ip;
//认证前
super.setAuthenticated(false);
}
public IpAuthenticationToken(String ip, Collection< ? extends GrantedAuthority> authorities){
super(authorities);
this.ip=ip;
//认证后
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.ip;
}
}
封装了用户ip的token类
public class IpAuthenticationProvider implements AuthenticationProvider {
final static Map ipAuthorityMap=new ConcurrentHashMap<>();
//维护一个权限Map
static {
ipAuthorityMap.put("127.0.0.1",new SimpleGrantedAuthority("ROLE_ADMIN"));
ipAuthorityMap.put("10.236.69.103",new SimpleGrantedAuthority("ROLE_USER"));
ipAuthorityMap.put("127.0.0.5",new SimpleGrantedAuthority("ROLE_DBA"));
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//IpAuthenticationToken 是authentication的实现类
IpAuthenticationToken ipAuthenticationToken = (IpAuthenticationToken) authentication;
String ip = ipAuthenticationToken.getIp();
SimpleGrantedAuthority simpleGrantedAuthority = ipAuthorityMap.get(ip);
if (simpleGrantedAuthority!=null){
return new IpAuthenticationToken(ip, Arrays.asList(simpleGrantedAuthority));
}
return null;
}
@Override
public boolean supports(Class> authentication) {
//只支持IPAuthentication进行认证
return (IpAuthenticationToken.class.isAssignableFrom(authentication));
}
}
负责ip验证的provider
public class IpAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
IpAuthenticationProcessingFilter(){
super(new AntPathRequestMatcher("/ipVerify"));
}
/**
* 在AbstractAuthenticationProcessingFilter的DoFilter方法中被调用
* @param request
* @param response
* @return
* @throws AuthenticationException
* @throws IOException
* @throws ServletException
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String hostIp=request.getRemoteHost();
return getAuthenticationManager().authenticate(new IpAuthenticationToken(hostIp));
}
}
负责sercurity验证的过滤器.
@Configuration
public class AppSecurityConfiger extends WebSecurityConfigurerAdapter {
@Autowired
private IpAuthenticationProvider ipAuthenticationProvider;
@Autowired
private AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;
@Bean
public IpAuthenticationProvider ipAuthenticationProvider(){
return new IpAuthenticationProvider();
}
/**
* 这里会覆盖configure中的SuccessHandler和异常的配置
* @param authenticationManager
* @return
*/
IpAuthenticationProcessingFilter ipAuthenticationProcessingFilter(AuthenticationManager authenticationManager){
IpAuthenticationProcessingFilter ipAuthenticationProcessingFilter = new IpAuthenticationProcessingFilter();
//添加认证管理器
ipAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager);
//添加成功处理器
ipAuthenticationProcessingFilter.setAuthenticationSuccessHandler(appAuthenticationSuccessHandler);
//添加失败处理器
ipAuthenticationProcessingFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/myError"));
return ipAuthenticationProcessingFilter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(ipAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("开始配置权限...............5");
//过滤静态登录页面和静态资源,这里的/路径都是指的是controller请求路径并不是指静态页面路径
http.authorizeRequests()
.antMatchers("/ipLogin","/js/**").permitAll()
.antMatchers("/","/home").hasRole("USER")
.antMatchers("/admin/**").hasAnyRole("ADMIN","DBA")
.antMatchers("/dba/**").hasAnyRole("DBA")
.anyRequest().authenticated()
.and().csrf().disable()
.formLogin()
.loginPage("/ipLogin")
// .successHandler(appAuthenticationSuccessHandler)
// .failureForwardUrl("/myError")
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/accessDenied");
//这里的得注意插入过滤器的位置
http.addFilterBefore(ipAuthenticationProcessingFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
}
}
这里我舍去了原文中LoginUrlAuthenticationEntryPoint的配置,选择直接在configure中配置验证拦截点的配置,另外发现新增的ipFilter的处理跳转的successHandler和failureForwardUrl无法在configure中配置,会失效
(四)以UsernamePasswordAuthenticationFilter为例分析sercurity的核心流程
WebSecurityConfigurerAdapter会获取到sercurity相关的filterChain(这部分源码没找到),然后挨个执行filter中的doFilter方法,每个filter都会继承抽象类AbstractAuthenticationProcessingFilter.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Request is to process authentication");
}
Authentication authResult;
try {
//在UsernamePasswordAutheticationFilter中被覆盖
authResult = attemptAuthentication(request, response);
if (authResult == null) {
// return immediately as subclass has indicated that it hasn't completed
// authentication
return;
}
sessionStrategy.onAuthentication(authResult, request, response);
}
catch (InternalAuthenticationServiceException failed) {
logger.error(
"An internal error occurred while trying to authenticate the user.",
failed);
unsuccessfulAuthentication(request, response, failed);
return;
}
catch (AuthenticationException failed) {
// Authentication failed
unsuccessfulAuthentication(request, response, failed);
return;
}
// Authentication success
if (continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
//调用seccessHandler进行调整控制
successfulAuthentication(request, response, chain, authResult);
}
usernamePasswordAuthenticationFilter:
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
providerManager:遍历各个provider进行验证
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Class extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
Authentication result = null;
boolean debug = logger.isDebugEnabled();
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
if (debug) {
logger.debug("Authentication attempt using "
+ provider.getClass().getName());
}
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException e) {
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw e;
}
catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
}
catch (AuthenticationException e) {
lastException = e;
}
}
if (result == null && parent != null) {
// Allow the parent to try.
try {
result = parent.authenticate(authentication);
}
catch (ProviderNotFoundException e) {
// ignore as we will throw below if no other exception occurred prior to
// calling parent and the parent
// may throw ProviderNotFound even though a provider in the child already
// handled the request
}
catch (AuthenticationException e) {
lastException = e;
}
}
if (result != null) {
if (eraseCredentialsAfterAuthentication
&& (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data
// from authentication
((CredentialsContainer) result).eraseCredentials();
}
eventPublisher.publishAuthenticationSuccess(result);
return result;
}
// Parent was null, or didn't authenticate (or throw an exception).
if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage(
"ProviderManager.providerNotFound",
new Object[] { toTest.getName() },
"No AuthenticationProvider found for {0}"));
}
prepareException(lastException, authentication);
throw lastException;
}
abstractUserDetailsAuthenticationProvider:调用userDetailService加载数据库里的user数据,并调用daoAuthenticationProvider的
additionalAuthenticationChecks进行账号密码匹配验证.
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.onlySupports",
"Only UsernamePasswordAuthenticationToken is supported"));
// Determine username
String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
: authentication.getName();
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
if (user == null) {
cacheWasUsed = false;
try {
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
}
catch (UsernameNotFoundException notFound) {
logger.debug("User '" + username + "' not found");
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
else {
throw notFound;
}
}
Assert.notNull(user,
"retrieveUser returned null - a violation of the interface contract");
}
try {
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);
}
catch (AuthenticationException exception) {
if (cacheWasUsed) {
// There was a problem, so try again after checking
// we're using latest data (i.e. not from the cache)
cacheWasUsed = false;
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);
}
else {
throw exception;
}
}
postAuthenticationChecks.check(user);
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
Object principalToReturn = user;
if (forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
return createSuccessAuthentication(principalToReturn, authentication, user);
}
userDetailService加载数据库中国的user信息
@Service
public class SystemUserSerivce implements UserDetailsService {
@Autowired
private PermissionMapper permissionMapper;
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User myUser =userMapper.selectUserByUsername(s);
List permissions = permissionMapper.selectPermissionsByUserName(s);
List grantedAuthorities = new ArrayList<>();
for(Permission permission:permissions){
String permissionCode = permission.getPermissionCode();
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permissionCode);
grantedAuthorities.add(grantedAuthority);
}
//这里provider需要的是springSecurity的user对象
return new org.springframework.security.core.userdetails.User(s,myUser.getPassword(),grantedAuthorities);
}
}
daoAuthenticationProvider 账号密码匹配
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
如果验证通过则abstractUserDetailsAuthenticationProvider会调用createSuccessAuthentication将权限信息也塞入token,并返回,如果验证不通过继续循环下一个provider
protected Authentication createSuccessAuthentication(Object principal,
Authentication authentication, UserDetails user) {
// Ensure we return the original credentials the user supplied,
// so subsequent attempts are successful even with encoded passwords.
// Also ensure we return the original getDetails(), so that future
// authentication events after cache expiry contain the details
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
principal, authentication.getCredentials(),
authoritiesMapper.mapAuthorities(user.getAuthorities()));
result.setDetails(authentication.getDetails());
return result;
回到filter,验证通过,并且返回了一个新的authentication ,包含了用户信息和权限,successfulAuthentication调用执行successHandler开始根据权限进行跳转
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
rememberMeServices.loginSuccess(request, response, authResult);
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request, response, authResult);
}
这里以simpleUrlAuthenticationSuccessHandler为例:
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
handle(request, response, authentication);
clearAuthenticationAttributes(request);
}
handler就是我们重写的覆盖的方法
protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("开始根据权限判断将要跳转的页面................");
String url=determineTargetUrl(authentication);
redirectStrategy.sendRedirect(request,response,url);
}
protected String determineTargetUrl(Authentication authentication){
String url="";
Collection extends GrantedAuthority> grantedAuthorities = authentication.getAuthorities();
List roles=new ArrayList<>();
for(GrantedAuthority grantedAuthority:grantedAuthorities){
roles.add(grantedAuthority.getAuthority());
}
//这里返回路径重定向,同样返回的是controller请求路径,并不是指静态文件的路径
if(roles.contains("ROLE_ADMIN")){
return "/admin";
}else if(roles.contains("ROLE_DBA")){
return "/dba";
}else if (roles.contains("ROLE_USER")){
return "/home";
}else {
return "/accessDenied";
}
}
至此,sercurity的核心流程全部结束.