萋小磊 发表于 2019-1-23 20:43

Spring security 初体验

本帖最后由 萋小磊 于 2019-1-23 21:14 编辑

Spring Security 初体验导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.2.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>cn.runjava.security</groupId>
   <artifactId>spring-security</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>spring-security</name>
   <description>Demo project for Spring Boot</description>

   <properties>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-security</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <optional>true</optional>
      </dependency>

      <dependency>
         <groupId>cn.hutool</groupId>
         <artifactId>hutool-all</artifactId>
         <version>4.1.19</version>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      
   </dependencies>
   
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>



认证过程
package cn.runjava.security.springsecurity.system.security;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
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.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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

/**
* @author 郑查磊
*/
@Slf4j
@Component
public class UserDetailsServiceRunJava implements UserDetailsService {


    private final String ROLE = "ROLE_";

    /**
   * 密码加密
   */
    @Autowired
    private
    PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

      // 查询出用户角色信息
      String password = username;

      // 加密后的密码
      String encodePassword = passwordEncoder.encode(password);

      // 账户是否启用 激活的概念 如果用户已启用,则设置为 true
      boolean enable = true;
      // 账户是否过期 如果帐户尚未过期,则设置为 true
      boolean accountNonExpired = true;
      // 密码是否过期 如果凭据未过期,则设置为 true
      boolean credentialsNonExpired = true;
      // 账户为被锁定 如果帐户未锁定,则设置为 true
      boolean accountNonLocked = true;
      // 权限集合 如果他们提供了正确的用户名和密码并且启用了用户,则应授予调用者权限。不是空的。
      ArrayList<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
      // 默认添加一个角色 为admin
      grantedAuthorityList.add(new SimpleGrantedAuthority(ROLE + "ADMIN"));
      // 添加一个权限为 queryUser
      grantedAuthorityList.add(new SimpleGrantedAuthority("queryUser"));
      // 简单版本 默认为true避免这些 概念性的设置
//      new User(username, encodePassword, grantedAuthorityList);
      User user = new User(username, encodePassword, enable, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorityList);
      log.info("登录认证:" + JSONUtil.toJsonPrettyStr(user));
      return user;
    }

}

Spring security config
package cn.runjava.security.springsecurity.system.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
* @author 郑查磊
*/
@Order(99)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class SecurityWebApplicationInitializerRunJava extends WebSecurityConfigurerAdapter {


    @Bean
    public PasswordEncoder getPasswordEncoder() {
      return new BCryptPasswordEncoder();
    }


    /**
   * 退出认证后do....
   */
    @Autowired
    private LogoutSuccessHandlerRunJava logoutSuccessHandler;

    /**
   * 认证成功后的处理
   */
    @Autowired
    private AuthenticationSuccessHandlerRunJava authenticationSuccessHandler;


    /**
   * 失败后的处理
   */
    @Autowired
    private AuthenticationFailureHandlerRunJava authenticationFailureHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http
                // 禁用 csrf-- 这里如果开启了 iframe 会出错 详细情况不清楚
                .csrf().disable()
                // 在这里的authorizeRequests 权限访问路径
                .authorizeRequests()
                // localhost:8080/admin
                // 例如 resources 下所有的请求 还有signupabout 的请求 都可以任意访问
                .antMatchers("/resources/**", "/signup ", "/about", "/system/logout", "/system/login.html").permitAll()
                // admin 下所有请求 需要admin 角色才能访问
                .antMatchers("/admin/**").hasRole("ADMIN")
                // db 请求 需要同时拥有 ADMIN 和 DB的角色
                .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
                // 剩下所有的 请求 都必须经过身份认证 也就是 login
                .anyRequest().authenticated()


                .and()
                // 基于表单认证
                .formLogin()
                // 认证地址
                .loginProcessingUrl("/login")
                //认证页面 需要配置一下
                .loginPage("/system/login.html")
                // 认证时候的 用户名参数
                .usernameParameter("username")
                // 认证时候的 密码参数
                .passwordParameter("password")
                // 认证成功后的处理
                .successHandler(authenticationSuccessHandler)
                // 失败后的处理
                .failureHandler(authenticationFailureHandler)
                // 认证失败转跳的路径
//                .failureForwardUrl("/logerror.html")
                // 认证成功后转跳的页面
//                .successForwardUrl("/index.html")

                .and()
                // 设置退出认证URL
                // 触发注销的URL(默认值为/logout)如果启用了CSRF保护(默认),则请求也必须是POST。
                .logout().logoutUrl("/logout")
                // 退出认证成功 跳到认证页面 /login?logout
//                .logoutSuccessUrl("/login.html")
                // 这里设置退出认证后的一些操作
                .logoutSuccessHandler(logoutSuccessHandler)
                // 退出时候注销sessiontrue
                .invalidateHttpSession(true)
                // 退出时删除的cookie信息
                .deleteCookies("user");
    }


}


退出登录Handler


package cn.runjava.security.springsecurity.system.security;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* @author 郑查磊
* @TODO 退出登录后要做的事情 do....
*/
@Slf4j
@Component
public class LogoutSuccessHandlerRunJava implements LogoutSuccessHandler {

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
      log.info("退出登录!" + JSONUtil.toJsonPrettyStr(authentication));
      response.sendRedirect("/system/logout.html");
    }
}

登录成功Handler
package cn.runjava.security.springsecurity.system.security;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* @author 郑查磊
* @TODO 登录成功后做的事情
*/
@Component
public class AuthenticationSuccessHandlerRunJava implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
      authentication.getDetails();
      if(authentication instanceof UsernamePasswordAuthenticationToken){
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) authentication;
            Object principal = usernamePasswordAuthenticationToken.getPrincipal();
            if(principal instanceof User){
                User user = (User) principal;
                // 设置到cookie 中 该用户的 登录账号
                response.addCookie(new Cookie("user",user.getUsername()));
                response.sendRedirect("/system/index.html");
            }
      }

    }

}
package cn.runjava.security.springsecurity.system.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* @author 郑查磊
* @TODO 失败后的处理
*/
@Slf4j
@Component
public class AuthenticationFailureHandlerRunJava implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

    }

}


编写自定义登录页面的controller

package cn.runjava.security.springsecurity.system.controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
* @author 郑查磊
*/
public class BaseController {

    /**
   * 拿到当前登陆的用户信息
   *
   * @param request
   * @return
   */
    public String getUserName(HttpServletRequest request) {
      HttpSession session = request.getSession();
      SecurityContextImpl securityContext = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT");
      return ((UserDetails) securityContext.getAuthentication().getPrincipal()).getUsername();
    }
}

package cn.runjava.security.springsecurity.system.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

/**
* @author 郑查磊
*/
@Controller
@RequestMapping("/system")
public class SecurityController extends BaseController {


    /**
   * 自定义登录页面
   *
   * @return
   */
    @GetMapping("/login.html")
    public String loginView() {
      return "/login";
    }

    /**
   * 首页
   *
   * @param request
   * @param model
   * @return
   */
    @GetMapping("/index.html")
    public String indexView(HttpServletRequest request, Model model) {
      model.addAttribute("username", getUserName(request));
      return "/index";
    }

    /**
   * 退出前提示
   *
   * @param request
   * @param model
   * @return
   */
    @GetMapping("/logout.html")
    public String logout(HttpServletRequest request, Model model) {
      model.addAttribute("username", getUserName(request));
      return "/logout";
    }

    /**
   * 登录失败
   *
   * @param model
   * @return
   */
    @GetMapping("/logerror")
    public String logerror(Model model) {
      return "/logerror";
    }
}


测试controller
package cn.runjava.security.springsecurity.controller;

import cn.runjava.security.springsecurity.entity.User;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

/**
* @author 郑查磊
*/

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/getUser")
    @PreAuthorize("hasAuthority('user')")
    public User getUser(Integer id) {
      return new User(id, "小石头", "不告诉你!");
    }

    @GetMapping("/addUser")
    @PreAuthorize("hasRole('ADMIN')")
    public User addUser(Integer id) {
      return new User(id, "小石头", "不告诉你!");
    }

    @GetMapping("/queryUser")
    @PreAuthorize("hasAuthority('queryUser')")
    public User queryUser(Integer id) {
      return new User(id, "小石头", "不告诉你!");
    }

}


用到的entity
package cn.runjava.security.springsecurity.entity;

import lombok.Data;

/**
* @author 郑查磊
*/
@Data
public class User {
    private Integer id;
    private String username;
    private String password;

    public User() {
    }

    public User(Integer id, String username, String password) {
      this.id = id;
      this.username = username;
      this.password = password;
    }
}

自定义的登录页面 首页等...

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello Spring Security</title>
</head>
<body>
    <h1 th:text="'登录成功! 尊敬的用户: ' + ${username}"></h1>
    <a th:href="@{/system/logout.html}">退出登录</a>
</body>
</html>

logerror.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录失败</title>
</head>
<body>
    <h1 th:text=""></h1>
    <a th:href="@{/login}"></a>
</body>
</html>

login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>自定义登录页面</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
</head>
<body>
    <div class="container">
      <form class="form-signin" method="post" th:attr="action=@{/login}">
            <h2 class="form-signin-heading">Please sign in</h2>
            <p>
                <label for="username" class="sr-only">Username</label>
                <input type="text" id="username" name="username" class="form-control" placeholder="Username" required
                     autofocus>
            </p>
            <p>
                <label for="password" class="sr-only">Password</label>
                <input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
            </p>
            <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
      </form>
    </div>
</body>
</html>


logout.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>退出登录成功!</title>
</head>
<body>
    <h1 th:text="'当前要退出的用户: ' + ${username}"></h1>
    <a th:href="@{/logout}">点击退出登录</a>
</body>
</html>


总结cn.runjava.security.springsecurity.system.security.UserDetailsServiceRunJava看懂此文章估计需要 基础 估计就是springmvc 和 spring 的一些 bean 概念 都不难...
这里写的多了一点 包括了 自定义登录页面和地址 都可以配置 详细看代码的注释即可主要是这个类 在用户登录时候的认证信息 添加角色 还有密码 没有写读取数据库
可以自己添加上去这里有一个概念的问题就是 ROLE 和 Authority 在spring security 中是没有这种概念的但是我们做设计的时候可以做一些变通
这里下次写 还有403错误 可以添加拦截 哈哈 下次补上其实配置不难 就是资源的权限配置以及
这个用户的认证过程2点其他的就是你自己对于接口的权限配置了注意的坑: .logoutSuccessUrl("/login.html") 和 .logoutSuccessHandler(logoutSuccessHandler) 只能存在一个 建议在Handler中 能做的更完善 可控项目
下载地址: 链接: https://pan.baidu.com/s/1_8xmY0mki2C0f8vmSXPW0w 提取码: 77jq
摘抄博客:https://www.runjava.cn/archives/spring-boot-security

萋小磊 发表于 2019-1-23 22:02

2015带你飞 发表于 2019-1-23 21:53
shiro了解一下,你这个东西太重了,虽然颗粒度很小但是shiro足够你用了

有时间去看看shiro但是能用security我就不会用shiro
后期转换oauth2简单

Titanic 发表于 2019-3-11 14:31

2019-03-11 14:31:36.718 ERROR 24244 --- w.a.UsernamePasswordAuthenticationFilter : An internal error occurred while trying to authenticate the user.

org.springframework.security.authentication.InternalAuthenticationServiceException: null
        at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:123) ~
        at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144) ~
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200) ~
        at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) ~
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: null
        at com.proaim.system.security.UserDetailsServiceRunJava.loadUserByUsername(UserDetailsServiceRunJava.java:40) ~
        at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:108) ~
        ... 54 common frames omitted

2019-03-11 14:31:36.718INFO 24244 --- .s.s.AuthenticationFailureHandlerRunJava : 登录失败:null

a7780425 发表于 2019-1-23 21:08

头皮发麻,基础都忘光了

萋小磊 发表于 2019-1-23 21:15

a7780425 发表于 2019-1-23 21:08
头皮发麻,基础都忘光了

其实大部分一些config 不难理解 其次就是auth的使用 这个相对于其他框架还算是容易懂的吧
使用起来也简单

ql_zth 发表于 2019-1-23 21:21

问下....如何去保证账户只有三处登录状态

萋小磊 发表于 2019-1-23 21:33

ql_zth 发表于 2019-1-23 21:21
问下....如何去保证账户只有三处登录状态

此处的登录状态是session级别的
不太懂你说的那种情况

2015带你飞 发表于 2019-1-23 21:53

shiro了解一下,你这个东西太重了,虽然颗粒度很小但是shiro足够你用了

一介书生 发表于 2019-1-30 09:31

先收藏下,

mijimoji 发表于 2019-1-30 17:31

一直用security

Titanic 发表于 2019-3-7 17:35

刚好,我也学一下,留着评分,回来反馈和问问题~
页: [1] 2
查看完整版本: Spring security 初体验